免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 24634215 | 回复: 24634215
打印 上一主题 下一主题

[C++] 开源项目Fiberized.IO召唤测试 [复制链接]

论坛徽章:
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
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-03-21 16:09 |只看该作者 |倒序浏览
本帖最后由 windoze 于 2015-08-31 23:19 编辑

如果你习惯于写每连接一个线程的程序,那试试这个吧 Fiberized.IO
你可以继续使用原来的模型,只需要把thread换成fiber,并使用库里面提供的stream类处理I/O,程序内部会使用一个m:n的green thread(fiber):kernel thread的映射,把blocking I/O的API替换成底层asynchronous I/O,并发能力和吞吐量都会大幅度提高。
这个库同时还提供C++11兼容的mutex/condition_variable实现,可以用于fiber之间的同步。

软件的文档在这里

2015年8月31日更新
昨天灵机一动,想到了一个简单的办法支持HTTP/1.1 Chunked encoding,本来想歪了以为要大动干戈,所以一直没做这个功能,找对了方法只花了一晚上就搞定了。
现在可以说Fiberized.IO的HTTP/1.1协议部分已经完整了,正在啃HTTP/2,看看有没有什么办法在不伤筋动骨的前提下把它也搞定。

2015年8月30日更新
加入了WebSocket服务端支持,一个简单的WebSocket echo例子在这里
暂时没空管Windows,所以新加入的与HTTP相关的功能还是不能用……

2015年5月28日更新
好吧我还是低估了VC的脑残程度,fibio的基础部分是可用的,但是HTTP部分由于我滥用C++11黑魔法,导致VC连续给我二十几个会心一击。
目前HTTP高地的战斗还在继续……
话说微软什么时候才能推出一个真正的C++编译器啊,现在这个C艹编译器实在是受够了!!!

2015年5月27日更新
项目到今天已经有一年多的历史了,今天Fiberized.IO终于可以在VC2015RC下编译并通过基本测试,这一切都是在至今也没有人给我赞助Windows机器的情况下进行的,有好心人愿意给我捐款不?
然而用CMake生成VC2015RC的工程文件似乎还是有问题,所以我手工创建了一组工程文件,正在检查看有没有绝对路径什么的,如果一切正常将在近期上传至GitHub。
PS. 有人知道怎么创建一个NuGet包吗?网上的教程似乎不是地球人写的,每个字都认得但连在一起什么意思居然不知道?!
PPS. 如果有人打算折腾C++11/14,敬请远离VC,血淋淋的教训呐……

12月2日更新:
支持Redis PUBSUB(终于……)和scan
加入了一个简单的Mustache模板,做HTTP server更简单了。
修了几个bug

11月12日更新
加入Apache Thrift支持,可以使用Fiberized.IO的架构实现Thrift客户端和服务端,比自带的TThreadedServer/TThreadPoolServer/TNonblockingServer更好、更容易的支持大并发。

11月更新
(比较)完整的HTTP服务端框架,支持HTTPS,加入了request routing和基本的cookie/请求参数解析,现在可以拿来写点Servlet干的事了
加入了一个URL client,支持HTTP和HTTPS,支持自动重定向跳转。
加入了一个基本的redis客户端,(几乎)支持所有的redis命令。

7月更新:
Fiber专用同步对象如mutex、condition_variable等的内部状态改用spinlock保护,在多CPU机器上可以提高一些效率。

6月更新:
完整支持C++11 future/promise,Boost.ASIO集成,重写了timeout实现,改正了之前实现中的race condition。

3月28日更新:
清理了io部分代码结构,加入SSL支持

3月24日更新:
在Linux下打开segment stack,Fiberized.IO测试程序已经成功创建1M个fiber,妈妈再也不用担心连接数太多了
test_http_server性能测试,在loopback上用"ab -k -c 100 -n 100000 http://localhost:23456/",qps超过200k (需要将test_http_server.cpp:128行注释掉,否则程序会自动退出)

完整的echo_server例子源代码在这里

论坛徽章:
3
巳蛇
日期:2013-10-03 10:41:48申猴
日期:2014-07-29 16:12:04天蝎座
日期:2014-08-21 09:24:52
2 [报告]
发表于 2014-03-21 16:55 |只看该作者
厉害啊,
看不懂的路过。

论坛徽章:
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
3 [报告]
发表于 2014-03-21 17:12 |只看该作者
本帖最后由 windoze 于 2014-03-21 17:14 编辑

简单的说就是这样,假定你有一个blocking的tcp_stream类,一个echo server大概会是这个样子:

  1. void servant(tcp_stream s) {
  2.     while(!s.eof()) {
  3.         // 从socket stream中读入一行
  4.         std::string line;
  5.         std::getline(s, line);
  6.         // 向socket中写入一行,std::endl会调用stream.flush(),确保数据都被发送出去
  7.         s << line << std::endl;
  8.     }
  9. }

  10. int main_entry(int argc, char *argv[]) {
  11.     // acceptor本质上就是一个listen socket
  12.     io::tcp::acceptor acc=io::listen(12345);
  13.     while(1) {
  14.         //blocking accept调用,返回一个connected socket,假定它有一个简单的basic_iostream兼容包装叫tcp_stream
  15.         tcp_stream stream(io::accept(acc));
  16.         // 创建一个工作线程处理该socket,detach说明这个thread不需要被join
  17.         std::thread(servant, std::move(stream)).detach();
  18.     }
  19.     return 0;
  20. }

  21. int main(int argc, char *argv[]) {
  22.     std::thread(main_entry, argc, argv).join();
  23.     return 0;
  24. }
复制代码
以上是一个极简单的1 connection per thread的echo server,只要并发连接数不多(比如只有几个或十几个,不超过CPU物理核数),它能很好的工作,效率远非任何非阻塞/异步模型可比。
但上面的程序也有致命问题,如果并发连接数太多,比如C10K甚至C100K的时候,CPU和OS无法有效的调度每个线程,甚至无法创建这么多的线程,导致程序效率骤降甚至崩溃。
Fiberized.IO的解决方案是采用coroutine/green thread/fiber(随便你叫什么,反正差不多),将10K甚至100K的fiber映射到一组固定尺寸的线程池上,在用户态进行调度,从程序角度看,它依然适用blocking I/O的模型,但在底层,所有blocking I/O的操作其实都是一个Async I/O的操作,通过适当的处理fiber状态并切换fiber context,保证每个工作线程的利用率最大化,减少线程争用,提高吞吐量和并发能力。
上面的程序很容易修改成fiber based,只需将std::thread换成fibio::fiber,并将main函数改成这样即可:

  1. #include <fibio/fiber.hpp>
  2. #include <fibio/stream/iostream.hpp>
  3. using namespace fibio;

  4. //  之前的程序片段
  5. ...

  6. // 4是线程池尺寸,你可以用std::thread::hardware_concurrency()代替以创建和CPU物理核数一致的线程池
  7. int main(int argc, char *argv[]) {
  8.     return fiberize(4, main_entry, argc, argv);
  9. }
复制代码

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
4 [报告]
发表于 2014-03-21 20:13 |只看该作者
回复 1# windoze

请教一下coroutine的实现方式?
boost,pth等程序库?Fibter/ucontext等平台特定的api?还是直接汇编地干活?

另外。。。 C++11已经很流行了么。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
5 [报告]
发表于 2014-03-21 20:50 |只看该作者
本帖最后由 OwnWaterloo 于 2014-03-21 20:50 编辑

回复 1# windoze

啊,我翻到了。。。
fiber_object.hpp (22)

  1. #include <boost/coroutine/coroutine.hpp>
复制代码
fiber_object.hpp (73)

  1.         typedef boost::coroutines::coroutine<after_step_handler_t>::pull_type runner_t;
  2.         typedef boost::coroutines::coroutine<after_step_handler_t>::push_type caller_t;
复制代码
继续请教。
如果用stackful的话会不会有移植性方面的问题?
而如果只用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
6 [报告]
发表于 2014-03-21 22:34 |只看该作者
回复 5# OwnWaterloo

Boost.context/Boost.coroutine可用于不少系统,\兼容性不是大问题,目前支持x86/x64/arm/mips/sparc/sparc64/ppc/ppc64上的Solaris/Linux/FreeBSD/Mac/Windows,基本涵盖了所有常见的系统,经实测在使用ELF的HaikuOS上也能用(虽然要hack一下makefile)。
stackful coroutine最大的好处就是和其它程序/库的兼容性好,因为在切换context之后,任何一个函数都无法“感觉到”新的context有什么不同,即使对于使用sjlj的变态库,只要小心点,也可以完全兼容。当然,使用stackful coroutine也要付出一些性能上的代价,但整体来说处于可接受范围内。

stackless看上去很美,但实际使用的时候会有很多问题。
一般认为stackless会有一些性能上的优势,但实际使用中你会发现stackless coroutine使用类似于CPS的方式串起整个执行链,所有“局部”变量都需要保存在一个执行链上每个块都可以访问到的区域,以C的实际情况而言,这个区域只能在堆上,而过度使用堆会导致cache局部性大打折扣。
另外一个巨大的问题就是错误处理,C++内置的异常处理机制完全不可用,每个pseudo blocking操作要么使用返回值处理异常(类似于node.js的错误处理),要么hack一点,在每个块外捕获异常,随CPS stack frame传递至下一个块重新抛出,直到被用户提供的异常捕获代码处理为止。

在开始这个项目之前,我曾经仔细考虑过这两者,最后还是选择了stackful coroutine,简单、兼容性好、性能损失很小,有这几点就足够了。

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
7 [报告]
发表于 2014-03-22 15:30 |只看该作者
不明觉厉,路过帮顶

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
8 [报告]
发表于 2014-03-22 19:03 |只看该作者
高大上,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
9 [报告]
发表于 2014-03-22 19:15 |只看该作者
回复 8# linux_c_py_php

晕,我该把你这话当赞美么……

既然你冒泡了,有几个问题想问你一下
1. 之前你搞过一个epoll+lua的东西,有什么办法可以快速创建一个lua state并且包含一组module么?
2. 在那个程序里,读写超时你是怎么处理的?

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
10 [报告]
发表于 2014-03-23 13:57 |只看该作者
windoze 发表于 2014-03-22 19:15
回复 8# linux_c_py_php

晕,我该把你这话当赞美么……


额, 必须是赞美啊。

1,我那个是单线程程序,就一个lua state,其他都是启的coroutine。。应该不会频繁加载module吧...
2,那个demo没实现lua的读写api。。。实现的话肯定是在c层跑个timer做超时啦。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP