开始之前:问题是关于deprecated "typed actors" module。很快就会被 akka-typed 取代,这是一个非常出色的解决方案,它避免了下面解释的缺点 - 如果您对类型化的 actor 感兴趣,请查看 akka-typed!
我将列举使用您提到的类型化actor 实现的一些缺点。但是请注意,我们刚刚合并了一个新的 akka-typed 模块,它将类型安全带回到了 akka actor 的世界。为了这篇文章,我不会深入探讨开发打字版本的原因如此艰巨的挑战,让我们现在回答“为什么不使用(旧)打字演员”的问题。
首先,它们从未被设计为工具包的核心。它们建立在 Akka 提供的消息传递基础设施之上。请注意,由于该消息传递基础架构,我们能够实现位置透明性和 Akka 众所周知的性能。他们大量使用反射和 JDK 代理来转换方法和消息发送。这是非常昂贵的(时间方面),并且与普通的 Akka Actors 相比,性能降低了大约 10 倍,请参阅下面的“乒乓”基准(使用两种样式实现,发送者告诉演员,演员回复 - 100.000 次) :
Unit = ops/ms
Benchmark Mode Samples Mean Mean error Units
TellPingPongBenchmark.tell_100000_msgs thrpt 20 119973619.810 79577253.299 ops/ms
JdkProxyTypedActorTellPingPongBenchmark.tell_100000_msgs thrpt 20 16697718.988 406179.847 ops/ms
Unit = us/op
Benchmark Mode Samples Mean Mean error Units
TellPingPongBenchmark.tell_100000_msgs sample 133647 1.223 0.916 us/op
JdkProxyTypedActorTellPingPongBenchmark.tell_100000_msgs sample 222869 12.416 0.045 us/op
(基准保存在akka/akka-bench-jmh 中,并通过sbt-jmh 插件使用OpenJDK JMH 工具运行。)
其次,使用方法对分布式系统进行抽象并不是一个好方法(哦,我怎么记得 RMI...让我们不要再去那里)。使用这种“看起来像一种方法”可以让您不再考虑消息丢失、重新排序以及在分布式系统中可能发生并且确实发生的所有事情。它还鼓励使用像def getThing(id: Int): Thing 这样的签名(使其“做错事太容易”)——这会生成阻塞代码——这对性能来说太可怕了!您确实希望保持异步和响应,这就是为什么在尝试与这些(基于代理的)类型化actor正常工作时最终会遇到大量future。
最后,你基本上失去了一个主要的 Actor 能力。 Actor 可以执行的 3 种规范操作是 1) 发送消息 2) 启动子 Actor 3) 根据收到的消息改变自己的行为(请参阅 Carl Hewitt 在 Actor Model 上的原始论文)。第三种能力用于对状态机进行精美建模。例如,您可以说(在普通的 akka 演员中)become(active) 然后become(allowOnlyPrivileged),在receive 实现之间切换 - 使有限状态机实现(我们也有一个DSL for FSMs)成为工作的乐趣。您无法在 JDK 代理类型的 Actor 中很好地表达这一点,因为您无法更改公开的方法集。一旦您开始使用状态机进行思考和建模,这是一个主要的缺点。
新希望(第 1 集):请查看由 Roland Kuhn 撰写的 the upcoming akka-typed module(预览版将很快包含在 2.4 版本中),我很确定你我会喜欢你会在类型安全方面找到的东西。而且,该实现最终将比当前的无类型参与者更快(这里省略 impl 细节,因为答案已经很长了 - 简短版本:基本上我们将通过新实现删除大量分配)。
我希望您会喜欢这个详尽的答案。随时在 cmets 或akka-user(我们的官方邮件列表)中提出后续问题。哈金快乐!