免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: waruqi
打印 上一主题 下一主题

[C] tbox新增stackless协程支持 [复制链接]

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
61 [报告]
发表于 2017-02-08 20:27 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 20:34 编辑
zylthinking 发表于 2017-02-08 19:50
回复 56# yulihua49

你并发的是 10000 个连接, 不是 10000 个协程;  你的每个协程都是在获得任务时创建 ...

又给你发了一个与之配套的ASIO-同步异步两用IO程序。50楼。
  1. cat AIO_tcp.c
  2. /**********************************************
  3. * @(#) SDBC 7.1 TCP RECV/SEND  Tools                      *
  4. * to suport coroutine
  5. **********************************************/
  6. #include <sys/socket.h>
  7. #include <sys/time.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <sc.h>

  11. #ifndef MIN
  12. #define MIN(a,b) ((a)<(b))?(a):(b)
  13. #endif

  14. static T_YIELD yield=NULL;

  15. T_YIELD get_yield()
  16. {
  17.         return yield;
  18. }

  19. T_YIELD set_yield(T_YIELD new_yield)
  20. {
  21. T_YIELD oldyield=yield;
  22.         yield=new_yield;
  23.         return oldyield;
  24. }

  25. //timeout for second
  26. int RecvNet(int socket,char *buf,int n,int timeout)
  27. {
  28. int bcount=0,br,ret;
  29. int i,repeat=0;
  30. int fflag=-1;

  31.         if(socket<0) return SYSERR;
  32.         if(!buf && n<0) return 0;
  33.         if(yield) {
  34.                 fflag=fcntl(socket,F_GETFL,0);
  35.                 if(fflag!=-1) fcntl(socket,F_SETFL,fflag|O_ASYNC|O_NONBLOCK); //异步操作
  36.         } else if(timeout>0) {
  37.                 struct timeval tmout;
  38.                 tmout.tv_sec=timeout;
  39.                        tmout.tv_usec=0;
  40.                        ret=setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&tmout,sizeof(tmout));
  41.                 if(ret) ShowLog(1,"%s:setsockopt errno=%d,%s",__FUNCTION__,errno,strerror(errno));
  42.         }

  43.         *buf=0;
  44.         br=0;

  45.         while(bcount<n){
  46.                 if((br=read(socket,buf,n-bcount))>0){
  47.                         bcount+=br;
  48.                         buf+=br;
  49.                         repeat=0;
  50.                         continue;
  51.                 }
  52.                 if(fflag==-1 && errno==EAGAIN) return TIMEOUTERR;
  53.                 if(br<=0 && errno && errno != EAGAIN){
  54.                     if(errno!=ECONNRESET)
  55.                         ShowLog(1,"%s:br=%d,err=%d,%s",__FUNCTION__,br,errno,strerror(errno));
  56.                     break;
  57.                 }
  58.                 if(bcount < n && fflag!=-1) { //切换任务
  59.                         if(repeat++>3) return -errno;
  60. /*
  61. yield:
  62. 1.找到当前线程的context。找不到返回-1;(后续任务以同步阻塞完成)
  63. 2.把事件提交给epoll,作为resume的条件。
  64. 3.swapcontext,挂起这个任务,线程回到epoll_wait,可以为别人服务了。
  65. 4.一旦这个任务的事件发生了,立即由epoll_wait激活一个线程,抓取相应的context,使用setcontext,恢复任务现场,返回0.
  66. 后续的动作就是继续NONBLOCK的IO。直至完成返回。
  67. */
  68. ShowLog(5,"%s:tid=%lx,socket=%d,yield to schedle bcount=%d/%d",__FUNCTION__,pthread_self(),socket,bcount,n);
  69.                         i=yield(socket,0,timeout);
  70.                         if(i<0) {
  71.                           if(timeout>0) {
  72.                                 struct timeval tmout;
  73.                                 tmout.tv_sec=timeout;
  74.                                 tmout.tv_usec=0;
  75.                                 ret=setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&tmout,sizeof(tmout));
  76.                           }
  77.                                 fcntl(socket,F_SETFL,fflag);
  78.                                 fflag=-1;
  79.                                 if(i==TIMEOUTERR) return i;
  80.                         }
  81.                 }
  82.         }
  83.         if(fflag!=-1) fcntl(socket,F_SETFL,fflag);
  84.         return bcount==0?-1:bcount;
  85. }

  86. int SendNet(int socket,char *buf,int n,int MTU)
  87. {
  88. int bcount,bw;
  89. int sz,i=0;
  90. int fflag=-1;
  91. size_t SendSize;

  92.         if(socket<0) return SYSERR;
  93.         if(yield) {
  94.                 fflag=fcntl(socket,F_GETFL,0);
  95.                 if(fflag != -1) fcntl(socket,F_SETFL,fflag|O_NONBLOCK); //异步操作
  96.         }
  97.         bcount=0;
  98.         bw=0;
  99.         if(MTU>500) SendSize=MTU;
  100.         else SendSize=n;
  101.         while(bcount<n){
  102.                 sz=MIN(n-bcount,SendSize);
  103.                 if((bw=write(socket,buf,sz))>0){
  104.                         bcount+=bw;
  105.                         buf+=bw;
  106.                 }
  107.                 if(bw<0&&errno!=EAGAIN) {
  108.                         ShowLog(1,"%s:err=%d,%s",__FUNCTION__,errno,strerror(errno));
  109.                         break;
  110.                 }
  111.                 if(bw < sz && fflag != -1) { //切换任务
  112. //ShowLog(5,"%s:tid=%lx,socket=%d,yield bw=%d/%d",__FUNCTION__,pthread_self(),socket,bw,sz);
  113.                     i=yield(socket,1,0);
  114.                     if(i<0) {
  115.                         fcntl(socket,F_SETFL,fflag);
  116.                         fflag = -1;
  117.                     }
  118.                 }
  119.         }
  120.         if(fflag != -1)  fcntl(socket,F_SETFL,fflag);
  121.         return bcount==0?-1:bcount;
  122. }
复制代码


论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
62 [报告]
发表于 2017-02-08 20:35 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 21:28 编辑
yulihua49 发表于 2017-02-08 20:27
又给你发了一个与之配套的ASIO-同步异步两用IO程序。50楼。

RecvNet:注意看54行,是直接进行read。多数情况直接就读出来了,不会进入后边的yield。
这个程序可以直接用于同步或异步场合,一般情况,yield是空的,就不会进入异步。在线程池服务器里会给它设一个yield函数,它就可以调用yield了,这时AIO_flag为真,task进入AIO模式,栈保持,线程逃逸。这个线程再要接受别的任务就会再分配栈。如果不调用yield,线程就不会逃逸,不会接受新任务,也就不会再分配栈。

一般的,异步调用会比同步慢。所以,这个程序尽量直接完成,多数不会进入异步状态,所以效率很高。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
63 [报告]
发表于 2017-02-08 21:37 |只看该作者
zylthinking 发表于 2017-02-08 19:50
回复 56# yulihua49

你并发的是 10000 个连接, 不是 10000 个协程;  你的每个协程都是在获得任务时创建 ...

所以,回到楼主的专题,stackless,使用起来限制太大,没什么实用价值。
自适应的协程池,是一个不错的解决方案。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
64 [报告]
发表于 2017-02-09 09:42 |只看该作者
本帖最后由 yulihua49 于 2017-02-09 15:56 编辑
zylthinking 发表于 2017-02-08 19:16
没说你的代码不好; 我说的是你之前的帖子有误导
你看看你之前说的:

你注意18楼,72行,如果需要的内存太多,不够用了,这个任务自动进入同步状态,不会耽误事的。这个系统设计就是这个原则,异步失败就改同步,不允许耽误事。
静态分配的协程,一旦资源不够,程序就无法运行。

实际的top显示,服务器的内存始终保持很小。

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
65 [报告]
发表于 2017-02-09 11:41 |只看该作者
yulihua49 发表于 2017-02-09 09:42
你注意18楼,72行,如果需要的内存太多,不够用了,这个任务自动进入同步状态,不会耽误事的。这个系统设 ...



好吧.
我本来也是蒙圈了感觉一个协程一个栈似乎很浪费; 看着你似乎能做到多协程共享栈才跑来问问;
昨天仔细想了想, 貌似64bit的机器根本不用考虑堆栈使用多少内存问题了; 反正至少几百G的可用虚拟空间不是只有最多3G可用的时代了;

我不打算再纠结这玩意了, 就这样吧

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
66 [报告]
发表于 2017-02-09 12:33 |只看该作者
zylthinking 发表于 2017-02-09 11:41
好吧.
我本来也是蒙圈了感觉一个协程一个栈似乎很浪费; 看着你似乎能做到多协程共享栈才跑来问问;
...

好的,就更没必要纠结stackless了。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
67 [报告]
发表于 2017-02-09 13:54 |只看该作者
回复 66# yulihua49

stackless coroutine的确没什么大用,但是单说stackless还是有用的,因为做了CPS变换之后,一个函数就可以无限递归,不用担心stack爆炸了。比如说tail recursion优化就可以认为是一种简化版的CPS变换,不光是节省了stack,而且性能也有提高。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
68 [报告]
发表于 2017-02-09 15:54 |只看该作者
windoze 发表于 2017-02-09 13:54
回复 66# yulihua49

stackless coroutine的确没什么大用,但是单说stackless还是有用的,因为做了CPS变 ...

同意。你可以在有栈的系统上自己做tail redcurion。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
69 [报告]
发表于 2017-02-10 14:58 |只看该作者
本帖最后由 yulihua49 于 2017-02-10 15:08 编辑
zylthinking 发表于 2017-02-09 11:41
好吧.
我本来也是蒙圈了感觉一个协程一个栈似乎很浪费; 看着你似乎能做到多协程共享栈才跑来问问;
...

一般的协程栈还是有问题。
如果支持10000个连接,每个连接一个协程,所需的栈是6M。那么需要60G的空间。这个仅仅是一个服务器的需求。
如果空间不够,连接时分配,可能连接到一定数量就崩溃了。可以采用动态commit的分配方式,更惨,不定什么时候就崩溃了。
采用我这个自适应栈池的方式,即使内存不够了,系统也不会崩溃,只不过后续的任务变成同步方式,不采用AIO罢了。稍等片刻系统就恢复如常。

分配不成就不分配,异步不成就同步,反正不会耽误事。系统具有超级鲁棒性。尤其是在遭受DDOS攻击时这个优点很明显。

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
70 [报告]
发表于 2017-02-10 20:38 |只看该作者
不错, 讨论的很激烈啊,很久没有来, 这个帖子不错,感觉技术含量很高的样子,一些细节的东西我也不懂,

我这边做代码遇到各种异步的类似的需求,总体上是靠call_back回调解决, 就是编程代码比较碎片化,但是性能还是不错的,限制少。

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP