免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: linux_c_py_php

[C++] [如何用状态机思想降低Server端开发复杂度? (GIT分支提供http server的实现框架示例) [复制链接]

论坛徽章:
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
发表于 2012-10-21 00:07 |显示全部楼层
本帖最后由 linux_c_py_php 于 2012-10-21 00:08 编辑

麻烦你读完代码与说明再做评论, 如果仅仅是select大家都会, 而且我也在上面的N楼里都提到过现在的绝大多数开发方式是怎么做的, 我觉得你没看到我要说的要点, 要点不是单线程epoll, 而是如何单线程完成I/O的情况下满足慢处理请求.

群雄逐鹿中原 发表于 2012-10-21 00:05
这种单线程server断select的方式,很久很久以前就很普及了。
只是写代码麻烦,很多“粗旷”的程序员,不喜 ...

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2012-10-21 00:26 |显示全部楼层
linux_c_py_php 发表于 2012-10-21 00:07
麻烦你读完代码与说明再做评论, 如果仅仅是select大家都会, 而且我也在上面的N楼里都提到过现在的绝大多数开 ...


如果真的单线程的话,你的慢处理阻塞操作时,event loop 就没法走下去,还是会影响IO。
说到底,将阻塞操作的各种状态转换到plugin的状态,阻塞操作本身,不是还要到另一个线程去运行?

明白的说,就是这样类比 --- select一堆文件而已。
阻塞操作放另一个线程,用pipe文件和select线程沟通。

说错莫怪

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2012-10-21 03:58 |显示全部楼层
回复 15# starwing83

那句话仅仅是吐槽而已。

当意识到自己之前写过的代码其实是在手工模拟一个语言特性后。。。  谁还愿意继续做手工模拟这种搓事?
至少我如果我还有得选 —— 在不一定非C不可的情况下 —— 就不会再去做这种事。

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
发表于 2012-10-21 04:13 |显示全部楼层
回复 16# linux_c_py_php


    我说有几个不是说这个技巧不实用或者曲高和寡。我的意思是这本来就是一个成熟的语言特性(coroutine),而你(和很多开源项目)所作的全部努力就是在C中模拟这个特性,这种事情(肯定是有意义的)是很吃力不讨好的,就是想说明这点。——额,也许会讨好,但是显而易见相比成熟的coroutine机制而言是很吃力的。没别的意思。

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
发表于 2012-10-21 04:16 |显示全部楼层
本帖最后由 starwing83 于 2012-10-21 04:20 编辑

回复 17# linux_c_py_php


    我做手机应用,也做过一两年手机网游开发,现在主要做一些开发工具。

其实倒不是很冷淡,只是这种思想已经在函数式语言和脚本语言大量出现了,以前看到continuation的时候的确很兴奋,见多了自然就见怪不怪了。Lua5.2的新yield机制(lua_callk)里面的lua_getctx就是专门为了你这种思想而提供的,可想而知在脚本领域和函数式领域是多么常见了。

服务器方面,说句实话,真没看出有什么有技术含量的东西- -有性能问题就用线程堆;而且现在国内的业务逻辑也很少用到很新奇的算法,大家都求稳。所以不感兴趣。但是客观的说,服务器领域的确有很令人兴奋和有挑战性的内容的,可惜服务器本身并不是。

想想连回三贴不好,我就编辑一下吧:我说的是python的greenlet,不是python之上的服务器框架。greenlet配合subprocessing可以直接用python做服务器,因为语言特性的优势写起来很简单,就是效率有问题,所以用的不多,既然有成熟框架,何必吃力不讨好。我这里的意思不是说python做服务器就很好,我只是举例告诉你这种思想是很普遍的。

论坛徽章:
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
发表于 2012-10-21 10:12 |显示全部楼层
好吧, 我认同服务端开发技术本身是没有什么技术含量的, 一旦掌握就无需费心的东西, 能够根据需求提出合理的设计方案就可以了.

我百度了一下greenlet, 的确是和本帖的实现方式应该是类似, 但毕竟那是别人的东西, 发帖就是看看谁对实现这个的原理或者实践感兴趣, 毕竟很多同学是喜欢研究服务端架构设计的, 虽然这里只是一个微观层面的具体实现细节, 还没涉及到多机交互, 但基础功扎实了才能灵活运用, 但我发现例子没给全容易造成理解困难...

如果是自己想开发个新项目, 并且把这个思想封成一个完全透明的框架, 可以让不了解框架实现的同学直接开发模块, 编译动态库后配置到框架中以便动态加载, 和我们为webserver开发一个module是一样的道理, 不过就像你说的, 多线程接入客户端其实是一个更快更稳定的解决方案, 开发难度更低, 逻辑也更清晰, 这一点我非常认同!!
我也不会无聊到自己开发这种Server, 因为几乎没有人接受我这样做(公司有公司的习惯, 异教徒必死), 除非我拿出一个完整的框架向大家展示一番, 估计能有几个人感觉还不错, 但我相信很多都是反对声, 这一点我相当有经验...

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
发表于 2012-10-21 10:38 |显示全部楼层
回复 26# linux_c_py_php


    恩,这段话我是觉得挺中肯的。

你可以试着看一下luvit:http://luvit.io/,这是一个基于Lua语言的,模仿node.js的服务器实现。之所以让你看这个而不是直接看node.js,是因为node.js本身是基于回调的——这一点和传统的服务器(也就是你写的那种)没有区别,该阻塞还是阻塞。而luvit因为采用了Lua,而Lua有原生的coroutine支持,所以它允许你采用coroutine的方式去写代码。非常非常方便。这个服务器最近准备拆分成几个子项目,以方便促进对coroutine编程手法的支持,以及对Lua本身(之前是基于LuaJIT——这也就是名字里it的来历)的支持。


我来举个例子,说明如果利用好了coroutine这种结构,程序应该怎么写。

比如说,一个最简单的例子:你自己写的Server,有一个状态转移,就是从request到response,假设中间要做十件很浪费十件的事情,怎么办呢?

你的代码已经给出了非coroutine的模拟式写法:每个StateMachine里面的状态判断十次条件是否满足,满足了就OK,否则就NOT OK,对吧?

这是什么呢?这几乎就是人手在手写机器编译for循环的过程!(仔细思考这种说法),假设是Lua,会怎么写呢?非常简单:
  1. function handler(request) -- before request
  2.    -- request
  3.    -- after request
  4.    -- before responce
  5.    local rep = response(request)
  6.    -- responce
  7.    local result
  8.    for i = 1, 10 do
  9.       result = collect(result, dosomething())
  10.    end
  11.    -- after responce
  12.    return response(result)
  13. end
复制代码
我标出了每个状态,你发现了什么没?它们是串行的!我并没有做任何处理就完成了状态转移。原理是什么呢?

状态机本身应该是由编译器自己产生的,而且编译器可以很清楚地知道某个状态是否可以跳过(见上),那么就可以优化。如果语言支持coroutine(如Lua),那么它可以让函数在一个地方“暂停”,然后执行其他的东西,一旦条件允许,就会唤醒暂停的地方,继续执行。我们假设每个上面的函数handler处理一个链接,假设当前来了第101个客户,我们看一下流程:

1. 101个客户连接服务器
2. 服务器产生request对象,此对象包含coroutine的实例(就是个数据结构,大概84个字节)
3. 服务器用handler初始化coroutine,并执行这个coroutine
4. (现在在coroutine内)handler一直执行到dosomething,然后dosomething内部有一个延时的操作,怎么办呢?dosomething向一个线程发送通知,要求进行某项工作,然后标记request为等待状态(其实就是把request加到一个等待队列里面去),然后直接**yield返回**到事件循环过程。
5. 事件循环阻塞或者继续处理其他的100个客户的事件。
6. 当101号dosomething完成任务的时候,一个信号被触发。事件循环本身负责处理这个信号(在你的框架里实际上是被包装了,是由libevent做这件事的),找到了那个request,恢复被yield的coroutine。
7. handler从dosomething返回,继续执行下一次循环。


看到了吧?这就是coroutine对你的框架的封装,是不是更简单呢?

PS:现在云风就在做这个东西。
   

论坛徽章:
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
发表于 2012-10-21 10:50 |显示全部楼层
本帖最后由 linux_c_py_php 于 2012-10-21 10:53 编辑

懂了, 就是说我是在应用层自己开发这些线程以及线程与主线程的交互的逻辑, 而用了coroutine之后, 这些工作都是透明的, 你就像写串行程序一样将一系列阻塞逻辑写上去, 但实际上运行的时候遇见阻塞逻辑就继续干其他事了, 直到阻塞的事在其他地方做完, 这里就会继续往下走.

我不是抵触这些机制的人, 任何好东西我非常愿意接纳, 脚本也是我程序生涯很重要的一部分, 但我不会lua, 不过我知道nginx和lua交互的很好, 就因为lua自身的超能力非常强大.

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
发表于 2012-10-21 12:44 |显示全部楼层
回复 28# linux_c_py_php


    对,你的理解很正确。

我倒是不是跟你推销这种策略(虽然它的确很好),我的意思是这种思想已经很普遍的被使用了。对服务器来说,这只是一种很基础很平常的知识,从客观上说谈不上惊艳(当然从感情上我理解的你的感受)。

不过说真的,我倒是推荐你在业余时间稍微学习一下Lua脚本语言。其manual非常短,就是一个网页而已(http://www.lua.org/manual/5.2/)。学习它的主要目的倒不是为了使用,是可以看到里面一些很优良的设计。关键是,你可以学习Lua的C API设计。我相信去思考这个设计,可以大大增强你设计C API的能力,进而理解C++的类的那一套的本质。这样的机会对开发者来说是难得的,我认识这是从开发者到架构设计者进化的一个机会。

最后,Lua本身的C实现非常优美,值得一看~

论坛徽章:
2
技术图书徽章
日期:2013-09-04 15:21:51酉鸡
日期:2013-11-01 21:20:20
发表于 2012-10-21 12:56 |显示全部楼层
回复 14# linux_c_py_php


你阐述的 eventloop,与nginx里的事件调度似乎很相似呀。nginx之所以高效的原因之一,就是因为采用了event调度轮询。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP