协程在Web服务器中的应用(配的图还不错)

      协程(纤程,微线程)这个概念早就有之,各家互联网公司也都有研究,但在国内各大论坛和大会热起来,还是今年的事。

      最近参与讨论开放平台建设和架构设计过程中,有同事提到了使用协程代替线程,能够很大幅度的提高性能。这引发了我们团队极大的兴趣和激烈的讨论。

首先,说明一下什么是协程。

      协程是用户态的线程。传统上线程的切换是由操作系统控制的,并且,每次切换都涉及到上下文的保存切换和用户态与内核态之间切换的过程。而协程的切换是由用户自己控制的,并且每次切换只涉及到上下文的保存与切换(即栈的出栈和入栈的过程)。由于同时可能存在多个线程操作同一个资源的问题,使用线程在必要的情况下需要使用“等待-加锁-释放”这样一套动作。而对于同一个线程中的协程同时操作同一个资源时,则没有这样的问题,因为同一个线程中的所有协程都是串行执行的。当然这样也导致了一个问题:架构在同一个线程中多个协程之上的程序,是无法利用多核资源的。最后,协程还有一个好处,则是协程能够产生更高可读性的代码。

在提出了协程之后,我也提供其他几个可供比较的概念。进程,线程,回调。 
      进程和线程就不多说了。了解一个进程包含一个或者多个线程,一个线程包含一个或者多个协程。在Linux中,创建进程和线程耗费的资源是一致的。
      这里强调一下回调。回调函数相对于协程而言,不会造成上下文的保存和切换,因此切换速度最快,但是也造成了使用回调函数没有上下文的问题。当需要上下文时,只能使用全局变量来保存,不符合大部分程序员的编程习惯。

然后,描述一下是因为什么问题导致了我们发现需要协程的。 
      在高并发应用中,尤其是Web应用,每台服务器都同时会有n多的连接和逻辑处理,每个连接之间没有逻辑关联。传统上对于每个连接请求,都会创建一个进程或者线程来处理该请求(先进一 点的会使用池化技术),这样如果某种类型的请求的处理线程由于各种问题导致处理耗时过长,则由于时间片全部耗费在此线程上导致问题非常严重,会因为一个请 求的问题导致所有请求都变慢或者不可用。
       我们希望当某个请求出现问题时,不会影响到其他的请求。

      纯粹的将请求种类强制划分开来,不同线程处理不同的请求是可以解决这个问题的,但是,终归会有部分CPU耗费在处理时间很长的请求上,另外,更换应用的时候,总会有大量配置甚至代码级别的更新,并非完美的解决方案。
      将同步处理过程转化为异步当然也可以解决此问题。但并非所有的同步处理过程都可以异步处理。

 

协程是如何解决这个问题的。

      《Windows核心编程 via C/C++》一书说:fiber(Windows中的协程叫做纤程fiber)只是为了使Unix的程序更加容易移植到Windows上来而提供的,建议Windows开发者不要使用fiber。我觉得这其实是不全对的,需要看场景。作者说不要使用fiber,是因为上下文的保存和切换可以由线程来解决而回调函数可以解决在同一线程中内的切换问题,一样不需要锁,并且速度更快。但在高并发应用中,则不一样,面对回调需要使用编程复杂的状态机和令人绝望的调试,fiber的上下文保存和切换则轻松的替换掉这些,并且编程实现上非常干净和漂亮。这是我们选择使用协程的原因。

      当然,问题并非协程就可以解决。首先异步IO与之结合是不可避免的。其次对任何一个Web服务器,后端都有非常多的Service的。一个Request,可能会涉及到多个Service。这就需要使用Furture模式,使任何一个Request只需要等待时间最长的一个Service而不用串行等待所有的Service。再次,比较复杂的是,对于协程的调度,我们需要实现一个调度器,使对协程的调用,总是能调度到请求Service完成的协程上,而没有完成的协程,则不会被调度。

      结合这些设计元素,一个使用协程的Web服务器就能高效的运作起来。

协程应用场景

http://blog.csdn.net/huyiyang2010/article/details/6042326

原文地址:https://www.cnblogs.com/findumars/p/7378800.html