免费注册 查看新帖 |

Chinaunix

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

[C] epoll + 非阻塞I/O 怎么改进才能变成 多线程 + epoll + 非阻塞I/O [复制链接]

论坛徽章:
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
21 [报告]
发表于 2014-11-05 20:00 |只看该作者
本帖最后由 yulihua49 于 2014-11-05 20:15 编辑
windoze 发表于 2014-11-05 19:54
回复 19# yulihua49

fiber和线程不是固定关系,所有fiber共享一个线程池。

那你的确是TPOOL模型。看看我楼上,我输的比较慢。
回答一下组包问题。
你说在fiber里体现为同步阻塞,那问题就来了,阻塞到何时为止?就牵出了组包的问题。

以我们的中间件来说,连接后先收26字节,发68字节。产生了一组秘钥,存在哪?应该是在fiber里,或者在应用context里。后边收到的所有内容都需要这个秘钥解密。
然后每次收36字节,根据参数再收N字节。。。。。。
然后会有一个登录认证过程,产生一组认证信息,也要存起来,能放在fiber里吗?
这怎么控制呢?

就是说,组包规则是应用制定的,可以自由设置吗?

论坛徽章:
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
22 [报告]
发表于 2014-11-05 20:59 |只看该作者
本帖最后由 windoze 于 2014-11-06 11:08 编辑

回复 21# yulihua49

当然是阻塞到条件满足为止啊,比如说你要读26个字节,那么tcp_stream::read(buf, 26)会一直阻塞到26个字节都被读出来为止,至于数据,对调用者来说当然是放在调用者提供的缓冲区里,(虽然tcp_stream内部其实有一个自己的缓冲区,多copy一次确实会影响效率,但程序简单了)。
例子中那个s << s.rdbuf()其实是偷了个懒,意思是说,程序一直阻塞,直到读到随便多少(但不超过stream内部缓冲区,目前是1500字节)数据,然后就把这些数据(阻塞)写出去。

你描述的问题,程序写出来大概就这样:

  1. void connection_handler(tcp_stream &s) {
  2.     char buf[26];
  3.     s.read(buf, 26);  // 这里会阻塞直到读到了26个字节,
  4.     // ...
  5.     char cmd[68];
  6.     fill_some_data(cmd, 68);  // 你自己的函数,生成68个字节的数据准备发送
  7.     s.write(cmd, 68);  // 这里会阻塞直到68个字节都发送完
  8.     // ...
  9. }
复制代码
每个阻塞点都会导致内部的scheduler切换到其它fiber继续执行,对于这个fiber来说所有的I/O都是最普通的同步阻塞操作,并且没有short read/write问题,但对于线程池来说内部进行的都是异步的非阻塞I/O。

简单说,这个库可以让你像早年间每连接一线程那样写程序,唯一的区别就是同样的程序结构可以处理更多的并发连接,一个进程中创建几百上千个线程就会很慢了,绝大多数时间都会花在线程切换上,但fiber或者说green thread创建和切换的成本都很低(目前的测试创建成本对比thread大约是100:1,切换成本大约相当于5次函数调用),所以创建几万个毫无压力,(压力测试中创建过2M个,程序还能跑)。

但由于是线程池结构,所以对于并发少但CPU密集的任务,这种结构就没有优势了,不过对于绝大多数网络服务端,coroutine+async I/O的结构都能极大的简化程序结构,同时保持高并发能力。

PS. C++的stream/streambuf框架一定要有个内部缓冲区,如果你觉得多一次copy很不爽,也可以用Fiberized.IO的Boost.ASIO集成功能,比如:

  1. void connection_handler(tcp_stream &s)
  2.     char buf[123];
  3.     boost::system::error_code ec;
  4.     size_t byte_read=boost::asio::async_read(s,
  5.         boost::asio::buffer(buf, sizeof[buf]),
  6.         boost::asio::transfer_at_least(123),
  7.         fibio::asio::yield[ec]);    // 用fibio::asio::yield当作ASIO中的completion handler,所有的boost::asio::async_xxx都可以变成fiber内的同步阻塞调用
  8.     // 这里byte_read应该等于123,否则ec.value()就不为0
  9. }
复制代码

论坛徽章:
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
23 [报告]
发表于 2014-11-06 11:10 |只看该作者
本帖最后由 yulihua49 于 2014-11-06 11:15 编辑
windoze 发表于 2014-11-05 20:59
回复 21# yulihua49

当然是阻塞到条件满足为止啊,比如说你要读26个字节,那么tcp_stream::read(buf, 2 ...

嗯。
如何挂起fiber,这个我还不会。哪段代码是挂起、解挂fiber?
s.read(buf,N);
当读出部分数据时,线程暂时放弃这个任务干别的去了。但函数没有返回,要等到全部收妥才返回。其中的挂起,解挂是怎么做的?

论坛徽章:
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
24 [报告]
发表于 2014-11-06 11:18 |只看该作者
本帖最后由 windoze 于 2014-11-06 11:19 编辑

回复 23# yulihua49

代码在 https://github.com/windoze/fibio ... io/detail/yield.hpp 里。
拿fibio::asio::yield当作Boost.ASIO的completion handler,会导致下面两个动作:
1、用一个回调函数当作Boost.ASIO的异步操作的callback,这个回调函数会在被调用时激活恢复调用异步操作的fiber
2、挂起当前fiber
接下来Boost.ASIO会在异步操作完成后调用第一步中的callback,这个callback会把之前挂起的fiber恢复。
这样在fiber层面,看到的就是一个同步阻塞操作。

具体的pause/activate实现在 https://github.com/windoze/fibio ... er/fiber_object.cpp 里。

论坛徽章:
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
25 [报告]
发表于 2014-11-06 14:51 |只看该作者
windoze 发表于 2014-11-06 11:18
回复 23# yulihua49

代码在 https://github.com/windoze/fibio ... e/fibio/fibers/asio ...

看到了。就置了标志。怎么实现的,还是不懂。需要系统学习一下调度原理。
其中,传输部分是用的ssl?

论坛徽章:
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
26 [报告]
发表于 2014-11-06 15:19 |只看该作者
本帖最后由 windoze 于 2014-11-06 15:20 编辑

回复 25# yulihua49

调度部分在one_step函数里,根据fiber状态决定下一步要干什么。
因为用了boost coroutine/context,所以在这段程序里其实也没什么细节,真要看细节你需要看boost context的代码,每个平台一段汇编,其实真正干的活也就是切了一下栈指针。

至于SSL神马的只是一个功能,不是必需品,当然可以直接用TCP。

论坛徽章:
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
27 [报告]
发表于 2014-11-06 21:08 |只看该作者
windoze 发表于 2014-11-06 15:19
回复 25# yulihua49

调度部分在one_step函数里,根据fiber状态决定下一步要干什么。

这个高级了,我想也是,C语言没办法切换执行栈。

论坛徽章:
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
28 [报告]
发表于 2014-11-06 22:37 |只看该作者
回复 27# yulihua49

C也可以啊,setjmp/longjmp就是干这个的,*nix下还有ucontext系列函数可用,功能都是一样的。
用boost.context其实就是为了方便和可移植性,前面说的两个,一个用起来很多坑,另一个在Windows下不能用。

论坛徽章:
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
29 [报告]
发表于 2014-11-07 10:22 |只看该作者
本帖最后由 yulihua49 于 2014-11-07 11:10 编辑
windoze 发表于 2014-11-06 22:37
回复 27# yulihua49

C也可以啊,setjmp/longjmp就是干这个的,*nix下还有ucontext系列函数可用,功能都 ...

linux也有ucontext系列调用?我要好好学习一下。
BSD有,linux有,找到了。
多谢指教,我要认真学一下,这样,我也可以写出异步转同步的程序啦。。。。

OSX:
/*
* These routines are DEPRECATED and should not be used.
*/
自OSX 10.6 这些东西就不能用啦!
编译有警告,执行出错。

LINUX倒是正确的,完全可用。

论坛徽章:
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
30 [报告]
发表于 2014-11-07 11:53 |只看该作者
回复 29# yulihua49

所以我才不用setjmp/longjmp/ucontext……
要知道Boost.context是目前唯一一个跨多个平台(包括Windows/OSX)还都能用的……
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP