先从著名的c10k问题谈起。有一个叫Dan Kegel的人在网上(http://www.kegel.com/c10k.html)提出:现在的硬件应该能够让一台机器支持10000个并发的client。然后他讨论了用不同的方式实现大规模并发服务的技术,归纳起来就是两种方式:一个client一个thread,用blocking I/O;多个clients一个thread,用nonblocking I/O或者asynchronous I/O。目前asynchronous I/O的支持在Linux上还不是很好,所以一般都是用nonblocking I/O。大多数的实现都是用epoll()的edge triggering(传统的select()有很大的性能问题)。这就引出了thread和event之争,因为前者就是完全用线程来处理并发,后者是用事件驱动来处理并发。当然实际的系统当中往往是混合系统:用事件驱动来处理网络时间,而用线程来处理事务。由于目前操作系统(尤其是Linux)和程序语言的限制(Java/C/C++等),线程无法实现大规模的并发事务。一般的机器,要保证性能的话,线程数量基本要限制几百(Linux上的线程有个特点,就是达到一定数量以后,会导致系统性能指数下降,参看SEDA的论文)。所以现在很多高性能web server都是使用事件驱动机制,比如nginx,Tornado,node.js等等。事件驱动几乎成了高并发的同义词,一时间红的不得了。

其实线程和事件,或者说同步和异步之争早就在学术领域争了几十年了。1978年有人为了平息争论,写了论文证明了用线性的process(线程的模式)和消息传递(事件的模式)是等价的,而且如果实现合适,两者应该有同等性能。当然这是理论上的。针对事件驱动的流行,2003年加大伯克利发表了一篇论文叫“Why events are a bad idea (for high-concurrency servers)”,指出其实事件驱动并没有在功能上有比线程有什么优越之处,但编程要麻烦很多,而且特别容易出错。线程的问题,无非是目前的实现的原因。一个是线程占的资源太大,一创建就分配几个MB的stack,一般的机器能支持的线程大受限制。针对这点,可以用自动扩展的stack,创建的先少分点,然后动态增加。第二个是线程的切换负担太大,Linux中实际上process和thread是一回事,区别就在于是否共享地址空间。解决这个问题的办法是用轻量级的线程实现,通过合作式的办法来实现共享系统的线程。这样一个是切换的花费很少,另外一个可以维护比较小的stack。他们用coroutine和nonblocking I/O(用的是poll()+thread pool)实现了一个原型系统,证明了性能并不比事件驱动差。

那是不是说明线程只要实现的好就行了呢。也不完全对。2006年还是加大伯克利,发表了一篇论文叫“The problem with threads”。线程也不行。原因是这样的。目前的程序的模型基本上是基于顺序执行。顺序执行是确定性的,容易保证正确性。而人的思维方式也往往是单线程的。线程的模式是强行在单线程,顺序执行的基础上加入了并发和不确定性。这样程序的正确性就很难保证。线程之间的同步是通过共享内存来实现的,你很难来对并发线程和共享内存来建立数学模型,其中有很大的不确定性,而不确定性是编程的巨大敌人。作者以他们的一个项目中的经验来说明,保证多线程的程序的正确性,几乎是不可能的事情。首先,很多很简单的模式,在多线程的情况下,要保证正确性,需要注意很多非常微妙的细节,否则就会导致deadlock或者race condition。其次,由于人的思维的限制,即使你采取各种消除不确定的办法,比如monitor,transactional memory,还有promise/future,等等机制,还是很难保证面面俱到。以作者的项目为例,他们有计算机科学的专家,有最聪明的研究生,采用了整套软件工程的流程:design review, code review, regression tests, automated code coverage metrics,认为已经消除了大多数问题,不过还是在系统运行4年以后,出现了一个deadlock。作者说,很多多线程的程序实际上存在并发错误,只不过由于硬件的并行度不够,往往不显示出来。随着硬件的并行度越来越高,很多原来运行完好的程序,很可能会发生问题。我自己的体会也是,程序NPE,core dump都不怕,最怕的就是race condition和deadlock,因为这些都是不确定的(non-deterministic),往往很难重现。

那既然线程+共享内存不行,什么样的模型可以帮我们解决并发计算的问题呢。研究领域已经发展了一些模型,目前越来越多地开始被新的程序语言采用。最主要的一个就是Actor模型。它的主要思想就是用一些并发的实体,称为actor,他们之间的通过发送消息来同步。所谓“Don’t communicate by sharing memory, share memory by communicating”。Actor模型和线程的共享内存机制是等价的。实际上,Actor模型一般通过底层的thread/lock/buffer 等机制来实现,是高层的机制。Actor模型是数学上的模型,有理论的支持。另一个类似的数学模型是CSP(communicating sequential process)。早期的实现这些理论的语言最著名的就是erlang和occam。尤其是erlang,所谓的Ericsson Language,目的就是实现大规模的并发程序,用于电信系统。Erlang后来成为比较流行的语言。

类似Actor/CSP的消息传递机制。Go语言中也提供了这样的功能。Go的并发实体叫做goroutine,类似coroutine,但不需要自己调度。Runtime自己就会把goroutine调度到系统的线程上去运行,多个goroutine共享一个线程。如果有一个要阻塞,系统就会自动把其他的goroutine调度到其他的线程上去。

一些名词定义:Processes, threads, green threads, protothreads, fibers, coroutines: what's the difference?

  1. Process: OS-managed (possibly) truly concurrent, at least in the presence of suitable hardware support. Exist within their own address space.
  2. Thread: OS-managed, within the same address space as the parent and all its other threads. Possibly truly concurrent, and multi-tasking is pre-emptive.
  3. Green Thread: These are user-space projections of the same concept as threads, but are not OS-managed. Probably not truly concurrent, except in the sense that there may be multiple worker threads or processes giving them CPU time concurrently, so probably best to consider this as interleaved or multiplexed.
  4. Protothreads: I couldn't really tease a definition out of these. I think they are interleaved and program-managed, but don't take my word for it. My sense was that they are essentially an application-specific implementation of the same kind of "green threads" model, with appropriate modification for the application domain.
  5. Fibers: OS-managed. Exactly threads, except co-operatively multitasking, and hence not truly concurrent.
  6. Coroutines: Exactly fibers, except not OS-managed.Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, iterators, infinite lists and pipes.Continuation: An abstract representation of the control state of a computer program.A continuation reifies the program control state, i.e. the continuationis a data structure that represents the computational process at a given point in the process' execution; the created data structure can be accessed by the programming language, instead of being hidden in the runtime environment. Continuations are useful for encoding other control mechanisms in programming languages such as exceptions, generators, coroutines, and so on.
  7. The "current continuation" or "continuation of the computation step" is the continuation that, from the perspective of running code, would be derived from the current point in a program's execution. The term continuations can also be used to refer to first-class continuations, which are constructs that give a programming language the ability to save the execution state at any pointand return to that point at a later point in the program.(yield keywork in some languages, such as c# or python)
  8. Goroutines: They claim to be unlike anything else, but they seem to be exactly green threads, as in, process-managed in a single address space and multiplexed onto system threads. Perhaps somebody with more knowledge of Go can cut through the marketing material.

Actor的原理的更多相关文章

  1. Actor模型原理

    1.Actor模型 在使用Java进行并发编程时需要特别的关注锁和内存原子性等一系列线程问题,而Actor模型内部的状态由它自己维护即它内部数据只能由它自己修改(通过消息传递来进行状态修改),所以使用 ...

  2. Actor模型及原理

    1.Actor模型 在使用Java进行并发编程时需要特别的关注锁和内存原子性等一系列线程问题,而Actor模型内部的状态由它自己维护即它内部数据只能由它自己修改(通过消息传递来进行状态修改),所以使用 ...

  3. 10 分钟了解 Actor 模型

    http://www.moye.me/2016/08/14/akka-in-action_actor-model/ 过去十几年CPU一直遵循着摩尔定律发展,单核频率越来越快,但是最近这几年,摩尔定律已 ...

  4. Actors编程模型

    Actors模型(Actor model)首先是由Carl Hewitt在1973定义, 由Erlang OTP (Open Telecom Platform) 推广,其 消息传递更加符合面向对象的原 ...

  5. 跟vczh看实例学编译原理——一:Tinymoe的设计哲学

    自从<序>胡扯了快一个月之后,终于迎来了正片.之所以系列文章叫<看实例学编译原理>,是因为整个系列会通过带大家一步一步实现Tinymoe的过程,来介绍编译原理的一些知识点. 但 ...

  6. Spark基本工作流程及YARN cluster模式原理(读书笔记)

    Spark基本工作流程及YARN cluster模式原理 转载请注明出处:http://www.cnblogs.com/BYRans/ Spark基本工作流程 相关术语解释 Spark应用程序相关的几 ...

  7. 认识VTK工作原理

    VTk通过数据流实现变信息为图形数据的. 数据流一般为:source-filter--mapper--actor--render--renderwindow--interactor. 要理解工作原理, ...

  8. 【Spring】Spring AOP实现原理

    Spring AOP实现原理 在之前的一文中介绍过Spring AOP的功能使用,但是没有深究AOP的实现原理,今天正好看到几篇好文,于是就自己整理了一下AOP实现的几种方式,同时把代理模式相关知识也 ...

  9. Atitit.并发编程原理与概论 attilax总结

    Atitit.并发编程原理与概论 attilax总结 1. 并发一般涉及如下几个方面:2 2. 线程安全性 ( 2.2 原子性 2.3 加锁机制2 2.1. 线程封闭3.3.1Ad-hoc线程封闭 3 ...

随机推荐

  1. phpstudy 出现“请自行检查是否安装VC9运行库??”问题 -- 缺少vc9库

    phpStudy是一款PHP调试环境的程序集成包,该程序包集成最新的Apache+PHP+MySQL+phpMyAdmin+ZendOptimizer,一次性安装,无须配置即可使用,是非常方便.好用的 ...

  2. 内核对TCP REUSEPORT的优化

    Q&A 当有人问起我关于reuseport的一些事的时候,我们的对话基本如下:Q1:什么是reuseport?A1:reuseport是一种套接字复用机制,它允许你将多个套接字bind在同一个 ...

  3. XAF学习笔记1

    写软件很多年了.看过的框架用过的框架非常多.一直想要一种框架,说不出的心烦重复的数据库设计,重复的Model生成,重复的界面设计 一直寻寻觅觅,终于找到一个框架,DEV的XAF,DEV控件用了N年了, ...

  4. 纯脚本组装Json格式字符串

    var answerStr = "["; for (var i in answer) { var data = $("input[name=QuestionItem_&q ...

  5. Android中如何查看so崩溃的log

    两种方法: 一.android自带的arm-eabi-addr2line工具 例如, - :: I DEBUG : # pc 0000d766 /system/lib/libtest.so - :: ...

  6. doxygen的使用(二)给代码添加javadoc风格的注释

    原创文章,欢迎阅读,禁止转载.本文记一下javadoc风格注释的写法,这些特殊格式的注释称作标签.按照这种规范写的注释才能生成到文档中. 块注释的写法 /** * @brief 这个块注释 * dox ...

  7. TCP头部结构

    3.2 TCP头部结构 TCP头部信息出现在每个TCP报文段中,用于指定通信的源端端口,目的端端口,管理TCP连接等,本节详细介绍TCP的头部结构,包括固定头部结构和头部选项. 3.2.1 TCP固定 ...

  8. C#与Swift异步操作的差异

    作为一个从C#转到Swift的小菜鸡...最近做一个简单的请求API解析Json数据的小程序上碰到一堆小问题.尤其是在异步请求的时候,用惯了C#的async/await写法,在写Swift的时候也按着 ...

  9. hdu 2896 AC自动机

    // hdu 2896 AC自动机 // // 题目大意: // // 给你n个短串,然后给你q串长字符串,要求每个长字符串中 // 是否出现短串,出现的短串各是什么 // // 解题思路: // / ...

  10. cognos制作报表流程

    第一章 创建报表 制作ReportStudio报表,步骤如下图所示: 第二章 添加查询 1.点击中间栏的查询资源管理器,然后点击查询,就可以新建查询.步骤如下图所示: 2.点击查询出现的页面: 3.在 ...