你不能在JVM上实现Actor, 绿色线程和CSP

该文是对目前Scala或Akka等基于JVM实现的Actor模型或CSP模型提出了质疑,认为因为JVM底层平台没有支持绿色线程,所以,导致Actor或类似Go语言的CSP模型的实现都会打了水漂。

当然,这是一个很重大的课题,希望后续有更多代码和实验能够验证,如果这个观点正确,对Scala或clojure都是致命打击,对于Erlang和GO语言是利好。

绿色线程在 Sun JVM 1.3以后就遭受抛弃,刚刚发布的Java 9也没有任何有关绿色线程的支持,无怪乎有人在感叹,Oracle虽然没有杀死Java,但它还会有时间这么做。

文章大概翻译如下:

我真的希望人们停止在JVM上建设Actor框架。我知道,在过去我自己也有这样做。无一例外,这些项目远远低于他们的预期目标。

然而,让我们退一步。到底是Actor,为什么每个人都这么热衷于它们?Actor模型描述了一组为了避免并发编程的常见问题的公理,并在学术界提供了一种并行计算的理论分析。具体实现可能大幅不同于他们的定义,但是最基本的Actor模型公理:

1.所有Actor状态是Actor本地的,外部无法访问。
2.Actor必须只有通过消息传递进行通信。可变信息不能别名。  
3.一个Actor可以响应消息:推出新Actor,改变其内部状态,或将消息发送到一个或多个其他参与者。
4.Actor可能会堵塞自己,但Actor不应该堵塞它运行的线程。

Actor的主要优势围绕人体工程学并发性。并发系统是经典的困难,因为没有顺序能够保证内存突变(程序员无法通过代码指定线程执行顺序,因为线程只听命于CPU调度),告诉哪些线程可能会执行一个给定的一段代码不可避免地变得很难。由于并发马虎出现的错误是出了名的难以解决,这些都是由于线程调度的不可预测性

通过Actor编程模型,大大缩小了最愚蠢设计导致的不良并发性。Actor和他们的服务员消息队列提供本地顺序保证,由于Actor只能一次处理一个消息,你得到了Actor内部本地状态的隐式锁定。Actor的轻量级特性也意味着它们可以产生的方式与问题域是1:1,减轻程序员需要多路复用的线程池。

..

不幸的是,Actor框架在JVM上不能充分约束编程环境避免并发缺陷,毕竟,你只是在普通线程内编写一个POJO对象(或scala clojure)。没有什么实际的方法限制代码能做什么,除非它明确不允许调用其他代码或循环。因此,即使使用字节码编织来实现协作的Actor框架在多任务时也不能完全保证非阻塞。这一点还是值得重复:没有根本改变JVM是如何工作的内部原理,你就不能保证任意一段代码不会被堵塞。

他们经常使用字节码bytecode编制weaving调整你的代码,Actor底部实现经常使用Java的 fork/join框架,其有臭名昭著的开销 ,尤其是当它涉及到小计算时,与vanilla 香草线程池相比是极其复杂的。Actor系统应该使并行计算很简单,但在JVM上轻量级线程系统我看过一点也不简单。

为了免得你认为我是一个Actor怀恨者,我真正喜欢的面向Actor编程。我一直是多年热情的Erlang程序员了,我曾经真正参加令人兴奋的添加此范式到Java的活动。然而,我现在相信,平台不支持这些轻量级并发库将永远是将所有努力打了一个水漂。我不是唯一持有这种观点的人

我们不应该信任厂商推动的什么宣言(Reactive宣言),用几十年的古老的部落的线程实现是误导的。我们应该建立尽可能简单的系统来解决我们的问题,以及如何测量他们,最有效地使用我们的机器。