免费注册 查看新帖 |

Chinaunix

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

[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
41 [报告]
发表于 2014-12-24 17:59 |只看该作者
回复 40# yulihua49

还有,你们的那个说法,fiber找个线程执行,我特不理解。如果一堆线程,没人找,那它在干啥?

还是在epoll_wait啊,我的做法和你的做法区别在于fiber stack什么时候创建,而不是怎么调度。
按照你的做法,fiber stack很浅,但是需要多次创建和销毁,我的做法是fiber stack比较大,但创建好了一直用。
话说回来,你一直在强调的那个1M是thread的stack尺寸,没人规定你自己创建的fiber也要用这个尺寸啊?这块内存是你自己分配的,理论上说你给它100个字节也可以啊,只要够用就行了。
而其所谓的1M stack也只是页表上的一个映射,只要你没用到那么多,OS也根本不会给这段地址空间分配那么多物理内存,地址空间这玩意儿在64位系统下完全没成本的说,2^64还不够你折腾的?
在32位系统上,至少在Linux下,split stack的功能是现成的,从4K开始,stack会按需扩大,根本不用担心浪费内存。

除非你还在写32位的windows程序,否则stack size根本不是问题,真搞不懂你到底在担心什么,你千万别说你还在Win32下写高并发服务器,这明显是姿势不对…………

论坛徽章:
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
42 [报告]
发表于 2014-12-25 09:37 |只看该作者
本帖最后由 yulihua49 于 2014-12-25 10:57 编辑
windoze 发表于 2014-12-24 17:59
回复 40# yulihua49

ucontext,epoll啊怎么可能是windows?
既然是malloc出来的栈,怎么可能动态扩展,我不明白。
即使栈都交换到swap分区,在频繁的OLTP活动中,还不是要频繁的换页啊?
如果栈空间可以无限制的使用,那根本就不需要fiber,TPC就可以了 ---- 这是我们这的一位资深大侠说的。
我同意这观点。TPC线程多了,调度开销大,但是还可以容忍,就是栈用的太多了。
1M是我的框架的基本需求(前边说了,传输压缩器就用了530K的栈),还要考虑应用的需求。
你看看38楼的那个调度器,栈没有被反复的创建和销毁,它是被保存在线程池里了,所以叫“协程池”,get -- release方式使用。
get时,只有在空池时创建。release时,满池才会销毁。每个线程,池里只容一个栈。

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

回复 42# yulihua49

你对这事有几点误解:
1、stack不一定是malloc出来的,只要你有一块可用的内存区域就行,随便什么方法都可以,mmap一般比较好用。
2、mmap的一个特点是不需要立刻实际分配物理内存,分配的只是页表项,除非你用MAP_POPULATE标志,否则只有用到的页才会真的分配物理内存,所以即便你mmap了1G的空间,只要你没用,物理内存就完全没浪费,swap时也不会有任何开销,像你说的1M这种尺寸根本不是问题。
3、和fiber相比,thread最大的不利之处就是切换的开销,如果你用过Tomcat之类的垃圾Web server你就知道sys占用率70%是一种怎样的痛了……用fiber就是为了轻量级切换,boost.context的切换只需几十ns,接近普通函数调用,而kernel thread的切换一般都在微秒级。系统创建thread时也是用mmap分配stack,在64位系统中,内存占用根本不是问题,你们那位“资深大侠”在这一点上经验有偏差。
4、split stack是GCC/Clang的一个增强功能,它的作用就是按需扩展stack,你先去看看手册再说。

除非是在32位Windows上,否则FPC就已经满足你需要了,不要依据一些不成立的理由把这事搞的这么麻烦。

论坛徽章:
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
44 [报告]
发表于 2014-12-25 14:48 |只看该作者
本帖最后由 yulihua49 于 2014-12-25 20:39 编辑
windoze 发表于 2014-12-25 14:41
回复 42# yulihua49

你对这事有几点误解:

我不了解mmap,学习了。
我之前一直是malloc。
线程切换需要3-7微秒(在当前这种CPU主频的级别下),这是我测到的,也是影响系统性能的关键点。
那个swapcontext,只需要几ns?

不过,基于epoll的AIO,线程切换是避免不了的。无论TPC,TPOOL,FPC。
过多的线程导致性能降低,这也是测的出来的,但是这种程度的损失,他们认为可以接受。他们也是讲,不要简单问题复杂化,TPC足矣。

不过我在这里get ---  release,肯定比换页要快多啦。

至于我这个程序,用于交易中间件,支持PPC,TPC,TPOOL。我是想,不进行大的修改就能在TPOOL模式下支持AIO。而且这个修改,不能破**坏对其他模式的兼容。
而且只有TPOOL模式需要AIO,其他的,SIO足矣。

论坛徽章:
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
45 [报告]
发表于 2014-12-26 09:59 |只看该作者
本帖最后由 yulihua49 于 2014-12-26 10:38 编辑
windoze 发表于 2014-12-25 14:41
回复 42# yulihua49

你对这事有几点误解:

过多的线程导致性能降低,就是调度阻塞的问题,可以用其他办法解决。
多数的交易中间件,都需要数据库,都配备数据库连接池。配置一定的规模,使得能够取得连接的线程数合适,他们进入活动状态,其他线程处于等待状态。这样就可以有效避免调度拥塞。
这样,TPC的调度拥塞问题可以轻松破解,FPC没有太大意义,反而把问题搞复杂了。

真正富有挑战的问题,就是内存问题。一个通信部件,占用大量内存这本不合理。你占用了大量内存,造成系统频繁换页,影响了业务模块的有效运行,还影响了这台机器的所有应用。一台机器可能不是给你一人使用。

我的方案,后台,交易服务器,采用TPC,前边加一个交易管理器,就是一个通信转发器,承受大量客户端的连接,对后台,有限的连接,就是连接池。这样后台的TPC就等效于线程池。区区一个通信转发器,要10-20G的内存?!。。。。。。内存有的是,可不是给你干这个的。

所以它采用TPOOL模型,原来是同步阻塞的,发现耽误事,一些长时间收发数据的客户端长期占有线程资源,会影响其他任务的转发。发现了你的fiber技术,用最少的代价改造成异步IO。
现在成功了,还是要感谢你:公布这个程序,也是交流一下,FPC原来也是可以节约内存的。

所以,我给你,还有楼主的建议,重**视内存问题。否则,FPC没有太大意义。

论坛徽章:
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
46 [报告]
发表于 2014-12-26 10:50 |只看该作者
回复 45# yulihua49

打开split stack之后一个fiber才用4K内存,你真觉得这是个大问题?10~20G?几百万个活动的fiber?敢问楼上你到底在写什么程序啊……

我觉得你还是没搞清当你说“占用内存”时你到底在说什么,“物理内存”和“虚拟内存的地址空间”可是完全不一样的。

以你自己说的为例,一个thread创建时“分配”了1M的stack,但这1M的stack此时真正占用的“物理内存”只有一个page,也就是4K。当你的thread调用链越来越深,才会继续请求OS为更多的stack“地址空间”分配“物理内存”。

运行top,你会看见两列,一列是"VIRT",另一列是"RES",第一列就是分配的“地址空间”,第二列才是这个进程真正占用的内存,对比一下两个数字你就知道有多大差距了。

thread最大的问题就是切换耗时,你要记得thread是“占先式调度”,也就是说即便什么特殊情况也没发生,当前thread都有可能随时被剥夺CPU,这个问题会随着thread数量增加而加剧,当你在8核电脑上创建1000个thread时你就会发现这个进程绝大部分时间都花在thread切换上了,真正留给进程自己干活的时间所剩无几。

论坛徽章:
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
47 [报告]
发表于 2014-12-26 11:31 |只看该作者
本帖最后由 yulihua49 于 2014-12-26 14:50 编辑
windoze 发表于 2014-12-26 10:50
回复 45# yulihua49

打开split stack之后一个fiber才用4K内存,你真觉得这是个大问题?10~20G?几百万 ...

i既然我配置了栈尺寸,肯定是要用到的,或差不多要用到的。(栈上空间是用户用的,栈下空间是系统用的,至少4k,你的4K肯定不够)
密集的OLTP,所有的fiber都会被激活的。这样,所有请求的空间都会被激活,实存不够,就等着换页吧。

当你在8核电脑上创建1000个thread---- 前边的帖子说了,利用连接池控制资源,活动的线程可以控制在合理范围内,不会引起调度拥塞。

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

回复 47# yulihua49

每个fiber 1M?每个fiber都是活动的?成千上万的session?如果真是这样的负载,你来告诉我你怎么省内存?

fiber stack到底是怎么分配的?在内存中的什么位置?你到底搞清楚了没?你那句“栈下面是系统用的”让我对这一点很疑惑你到底知不知道多thread/fiber的程序内存布局到底是什么样子的。

另外,split stack是什么意思你到底看手册了没?要是真的看了你来给我讲讲如果预分配的4K不够用时会发生什么事?

论坛徽章:
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
49 [报告]
发表于 2014-12-26 14:55 |只看该作者
本帖最后由 yulihua49 于 2014-12-26 15:26 编辑
windoze 发表于 2014-12-26 14:36
回复 47# yulihua49

每个fiber 1M?每个fiber都是活动的?成千上万的session?如果真是这样的负载,你来 ...

每个fiber 1M不算多,我框架就用了530K。所有的fiber都会被激活,就是呼入的客户端迟早会耗尽所有的fiber,我们必须按这个设计。
你fiber的栈,什么时候分配?初始化时?呼入时?还释放吗?

rsp之上时用户区,之下是系统用,无论是原理上和实测结果都是毋容置疑的,X64,栈下不留足4K,必死。这是前几天测出来的。
  1.                         uc->uc_stack.ss_size=save_stack_size+4096;
  2.                         uc->uc_stack.ss_sp=malloc(uc->uc_stack.ss_size+16);
  3.                         if(!uc->uc_stack.ss_sp) {
  4.                                 uc->uc_stack.ss_size=0;
  5.                                 uc=NULL;
  6.                                 fcntl(socket,F_SETFL,fflag);
  7.                                 continue;
  8.                         }
  9. //保存线程栈帧
  10.                         memcpy(uc->uc_stack.ss_sp+4096,(void *)(begin_stack-save_stack_size),save_stack_size);
  11. //将实际的rsp,rbp也调过来  这需要一段asm
  12.                         sp=set_sp(uc->uc_stack.ss_sp+4096);
复制代码
这是前几天的测试程序,本帖前边的代码是2048,会死,4096不会死。

split stack还没有看,是不是动态扩充的意思?即使如此,迟早会用到相当的尺寸。

如何节省栈,看38楼。

退一步,就算内存没问题,那TPC足矣,调度拥塞的问题可以用别的方法解决(我不会让1000个线程都动起来的),FPC就没必要了。

论坛徽章:
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
50 [报告]
发表于 2014-12-26 15:37 |只看该作者
回复 49# yulihua49

每个fiber 1M的内存用到了什么地方?是保存session数据吗?如果是这样,你用不用fiber有什么差别?就算不用fiber你这些数据放在哪儿?
如果保存的不是fiber数据,只是调用链上的局部变量,那么:1、你的程序该重写;2、再重复一遍,split stack就是干这个的,去看手册。

你说rsp之上之下云云,有没有想起来你的程序有多个thread?每个thread是不是有自己的stack和rsp?这些thread是不是共享同一个线性地址空间?你说的“系统区”到底在哪个thread的rsp之下?你还额外创建了若干stack,这些stack在活动时是不是也有自己的rsp?这么多stack在内存中怎么排列的?“用户区”和“系统区”到底在这个统一的线性地址空间的什么地方?话说这些问题你到底想清楚了没?

如果你创建了多个thread,进程的地址空间里就已经有多个stack了,每个活着的thread都有自己栈顶栈底和栈指针,这些stack是零零散散分布在整个进程地址空间的多个地方的。
rsp“之上”(往低位地址的方向)是你还没用到的stack,“之下”是你已经用了的stack,rsp的有效值范围就是你已经分配了的stack范围,超出这个范围就会stack over/underflow,OS创建的thread stack一般会在前后保留一个不映射物理地址的guard page来检测这种错误,但这些内存和“系统区”有半毛钱关系?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP