Scala Actor与底层并发编程机制异同之探讨

本篇文章的主题是Actor。对于不太了解Actor的读者们,可以先参考一下老赵的这篇《Actor模型的本质》。简单的说,Actor是一种天生为并行编程而存在的模型,在很多编程语言中都采用了这种模型,比如C#,Erlang以及Scala。本文是Code-o-matic博主Dimitris Andreou针对Scala的Actor模型展开的思考。

51CTO编辑推荐:Erlang的Actor回顾 顺畅的使用C# Actor

有人在Scala邮件列表的讨论中建议直接对比actors和锁的使用。下文是我的讨论,前面部分只是作为一种回应,而最后我总结了不少当前对于actor编程模型的关注点和问题。

将actors和底层并发编程(比如锁)做对比具有误导性。它不是这样一种情况:存在一些actors,它们之后是巨大的空白,然后是一些锁——然后我们不得不做出一些极端的选择。两者之间涉及更多的东西。例如,一台虚拟机中,在阻塞队列(或者,不久之后将成为的传输队列)的顶端实现消息传递是非常烦琐的。目前已经有executor框架,以及fork/join框架来提供线程池或者细粒度(fine-grained)的并行(parallelism)机制。(51CTO编辑推荐阅读:Java 7的细颗粒并行化)

此外,简化编程也必须付出代价,探讨其对性能的影响变得不再像以前那么容易,至少对我而言如此。例如:假定scala actors依赖于ForkJoinScheduler(也就是使用fork/join架构), 此处源自ForkJoinPool中的javadocs的引用将会很有意思:

ForkJoinPool在创建时会被指定一个并行等级(目标池的大小),该等级通过动态添加、挂起、恢复线程的方法来维持,即使一些任务正在等待其它任务也是如此。然而,在阻塞式IO或者非托管的异步系统中,这种调整没有被实现。

这就产生一些很明显、但我却很难告诉你答案的问题:

1. actors使用(阻塞式)IO会对性能产生什么影响?(我还没有看到提供给actors用户的类似警告)

2. 既然我们根据javadoc已经知道任务不会被加入,而receive()的阻塞式系统调用会陷入非托管的同步系统中,那么这对我们而言又意味着什么呢?

因此,简单化也似乎意味着以隐藏可能的重大优化作为代价,就像一个需要阻塞以加入子任务的线程一样,在其等待期间继续运行以及执行其它任务。

我不能确定最终的结论是什么。若顺利的话,3-4年内社区在这一方面的编程经验将会大大增加,我们将了解如何才能更好的使用这种很炫的工具,也将会知道什么时候改使用底层的并发服务程序。就我个人而言,截至目前为止,尽管我很希望使用actors,但底层工具的运用让我如鱼得水,因为我可以更容易分析我的代码的性能特征。很希望有人能够写一本优秀的Scala actors书籍——虽然目前并发的书也不错,但因为Scala还很新,所以这些数据关于actors的往往只有一章。读者若想了解除基础知识之外的东西,这些书籍所涵盖的内容还远远不够。

相关推荐