免费注册 查看新帖 |

Chinaunix

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

[C++] [转]ASIO 与协程 [复制链接]

论坛徽章:
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
11 [报告]
发表于 2015-02-27 14:30 |只看该作者
本帖最后由 yulihua49 于 2015-03-02 16:02 编辑
windoze 发表于 2015-01-20 17:56
回复 8# yulihua49

嗯,所以说光做coroutine+Async I/O是不够的,你总归要想办法和foreign thread通信, ...


这个AIO file 与协程结合的方案行吗?节后开发服务器都关了,暂时没办法测试。
通过eventfd,结合libaio和epoll。那个do_event是SDBC框架封装好的,与epoll调度器的协程接口。
  1. #include <stdio.h>
  2. #include <libaio.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <libaio.h>
  6. #include <sys/eventfd.h>

  7. #include <scsrv.h> //这个是SDBC特定的

  8. static int AIO_oper(int fd,char *buff,size_t iosize,int flg)
  9. {
  10. io_context_t myctx;
  11. int rc,num;
  12. uint64_t finished_aio;
  13. struct iocb iocb,*io=&iocb;
  14. struct io_event event;
  15. int     efd = eventfd(0, 0);
  16.         if (efd == -1) {
  17.                 return flg?write(fd,buff,iosize):read(fd,buff,iosize);
  18.         }

  19.         io_set_eventfd(io,efd);
  20.         io_queue_init(1, &myctx);
  21.         if(flg) io_prep_pread(io, fd, buff, iosize, 0);
  22.         else    io_prep_pwrite(io, fd, buff, iosize, 0);
  23.         rc = io_submit(myctx, 1, &io);
  24.         if(rc<0) {
  25.                 close(efd);
  26.                 io_destroy(myctx);
  27.                 return flg?write(fd,buff,iosize):read(fd,buff,iosize);
  28.         }
  29.         rc = do_event(efd,0,0);//yield to epoll
  30.        if(rc==0)  read(efd, &finished_aio, sizeof(finished_aio));
  31.         close(efd);
  32.         num = io_getevents(myctx, 1, 1, &event, NULL);
  33.         if(num>0) {
  34.                 if(event.res2==0) num=event.res;
  35.                 else num=-1;
  36.         }
  37.         io_destroy(myctx);
  38.         return num;
  39. }

  40. int AIO_read(int fd,char *buff,size_t iosize)
  41. {
  42.         return AIO_oper(fd,buff,iosize,0);
  43. }

  44. int AIO_write(int fd,char *buff,size_t iosize)
  45. {
  46.         return AIO_oper(fd,buff,iosize,1);
  47. }
复制代码
调用AIO_read或AIO_wrote就像read或write一样。所不同的就是中间可能yield过。
之前和之后可能不是同一个线程。
在SDBC交易中间件框架里采用AIO——file,倒不是性能如何如何,而在于在等待IO期间,线程yield去为别的客户服务了。
改善用户体验。

论坛徽章:
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
12 [报告]
发表于 2015-02-27 16:20 |只看该作者
回复 11# yulihua49

看起来还好啦,AIO+eventfd也是常见的做法,就是用flg标示read/write有点傻……

论坛徽章:
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
13 [报告]
发表于 2015-02-27 19:46 |只看该作者
本帖最后由 yulihua49 于 2015-02-27 19:52 编辑
windoze 发表于 2015-02-27 16:20
回复 11# yulihua49

看起来还好啦,AIO+eventfd也是常见的做法,就是用flg标示read/write有点傻……
那是因为除了r/w之外其他操作完全相同。那个myctx用作形参是否应该加&?

论坛徽章:
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
14 [报告]
发表于 2015-02-27 21:45 |只看该作者
回复 13# yulihua49

那个io_context_t是什么?记得linux AIO里的是aio_context_t?如果是aio_context_t,是不用加&,因为那个东西本来就是个指针。

论坛徽章:
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
15 [报告]
发表于 2015-02-28 09:52 |只看该作者
windoze 发表于 2015-02-27 21:45
回复 13# yulihua49

那个io_context_t是什么?记得linux AIO里的是aio_context_t?如果是aio_context_t ...

linux有两个:
aio:#include <aio.h>
       cc ..... -lrt

libaio: #include <libaio.h>
        cc ......  -laio

我这是后一种,它能结合epoll。前一种没查到如何结合epoll。

论坛徽章:
0
16 [报告]
发表于 2015-02-28 21:15 |只看该作者
本帖最后由 xphh2008 于 2015-02-28 21:19 编辑

回复 4# yulihua49


    思路有些问题。你的协程跨越线程,我不知道怎么做到的。从理论上说,协程应当只在一个线程内调度。

    也不是说一定要在一个线程内,但是跨线程的框架,就需要使用者自己去保证线程安全以及数据竞争,这是很麻烦的事。也有悖于利用协程的初衷。

    按我说,一个线程多个协程,在此基础上多线程。多线程间不要共同调度协程。

    另外sleep实现了吗?

论坛徽章:
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
17 [报告]
发表于 2015-03-02 10:26 |只看该作者
本帖最后由 yulihua49 于 2015-03-02 11:50 编辑
xphh2008 发表于 2015-02-28 21:15
回复 4# yulihua49

这个,我跟windoze差不多,都是线程池-协程,实现方法上,二者有差别。
单线程协程,并不是真正的并行计算。
我们是在并行计算的基础上,涉足协程的,就是把原来的线程池服务器协程化了。
所以,我们造轮子,是因为这种轮子根本找不到,需要自己造。

我们的做法:
原来的epoll - 线程池服务器,异步阻塞的,异步任务调度框架,在应用插件里使用同步阻塞IO。这时如果应用插件循环IO(比如长时间传输大文件)就会占死线程。需要在其等待IO时yield线程,一旦IO完成,resume之。
现在的做法,是在epoll发现一个请求时,建立该客户的fiber(makecontext)。调用应用插件,应用插件进行“同步阻塞IO” ,比如AIO_read。而在AIO_read内部,与应用逻辑无关的,透明的进行异步IO,在yield之前,把eventfd注册到epoll,然后进行:
swapcontext(当前fiber的ucontext,线程的ucontext); 这样就把线程交还给框架,继续epoll_wait(可能有许多线程都在epoll_wait)。
当IO完成时,触发eventfd,导致激活了一线程,它发现是个fiber,就进行resume(setcontext(fiber的ucontext))。直到插件完成任务返回,框架销毁fiber,并使这个TCB(状态机)进入等待该客户端下次请求的状态。
TCB,fiber,epoll等等对插件都是透明的,插件并不知道这些东西的存在。只不过我不敢重载read/write,它们需要调用AIO_read来代替之。

不过你说的一个线程多个协程,协程不跨越线程;然后是多个线程,倒是一个不错的思路。我想不好如何组织到我的框架里。
----每个线程一个epoll_fd。把TCB分配到不同的epoll_fd,不太容易做到均衡。
就是resume必须是yield的那个线程,不知怎样能实现这个控制。
一大堆线程在epoll_wait,哪个线程能抓住那个事件是没法控制的。

sleep没有实现,大概要用到timerfd了吧。
原则上不建议应用插件使用sleep类的函数。

做法跟这个差不多,准备好timerfd后,epoll-yield,resume后进行getevents。

论坛徽章:
0
18 [报告]
发表于 2015-03-02 20:15 |只看该作者
回复 17# yulihua49


    明白了,你的线程里就一个协程。

    sleep可以用epoll的超时时间实现。

    我的做法是一个fd固定在一个线程里,所以线程安全都不需要考虑了,对于使用者更友好。至于你说的均衡,我的建议是不需要多考虑。服务器在上万连接数下,各线程的负载其实是统计平均的。当连接数较少时,有可能不均衡,但连接数少,服务器也没什么压力,不均衡就不均衡吧!

论坛徽章:
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
19 [报告]
发表于 2015-03-03 13:01 |只看该作者
本帖最后由 yulihua49 于 2015-03-03 13:20 编辑
xphh2008 发表于 2015-03-02 20:15
回复 17# yulihua49

我的协程不属于哪个线程,但是线程某时刻可以有0或1个协程。在不同时刻可以参与不同的协程。每个协程不同时刻由不同线程来执行。
每个TCB(应用context),不活动时没有协程,活动时可能有一个协程,也可能没有。
至于fd,很难说,对于一个TCB,框架里有fd(一个或多个),应用插件里用多少fd,他们是否介入AIO都不好说。
何时将哪个fd投入epoll也不一定。这些情况极其复杂。幸好,这个复杂度都由框架承担,应用插件是一点也不知道的。
如上,框架向应用插件提供AIO_read/AIO_write,插件调用这个函数时,那个fd就是它自己产生的。框架还产生了eventfd。。

论坛徽章:
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
20 [报告]
发表于 2015-03-03 13:20 |只看该作者
回复 16# xphh2008

@yulihua49和我做的都不是通常意义上的coroutine,说它是M:N threading更准确
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP