Java中的Akka typed actors

3
我不明白为什么不使用TypedActorsAkka中。在Java中,使用反射(或者说是instanceof)来弥补模式匹配的缺失相当丑陋。
据我所知,TypedActors应该像一个门,连接你的软件中"Akka世界"和"非Akka世界"之间。但为什么我们不放弃所有面向对象的原则,直接使用反射呢?
为什么不想使用一个actor并确切地知道它应该响应什么?或者为了保持actor模型,为什么不创建一个消息层次结构,使用双重分派来激活actor中正确的方法(我知道你不应该将Actor作为参数传递,而是使用ActorRef)。
免责声明:我对Akka和这个模型很新,并且我还没有编写过一行使用Akka的代码,但只是阅读文档就让我头痛不已。

你也可以看一下为Java 8设计的Typed Actors。https://github.com/RuedigerMoeller/kontraktor - R.Moeller
3个回答

8

在我们开始之前:这个问题涉及已废弃的“类型化Actor”模块。该模块很快将被akka-typed所取代,它是对该问题的更好解决方案,避免了下面解释的缺点 - 如果你对类型化Actor感兴趣,请确保查看akka-typed!


我将列举使用您所提到的类型化Actor实现的一些缺点。请注意,我们刚刚合并了一个新的akka-typed模块,它为Akka Actors带来了类型安全。就本文而言,我不会深入探讨开发类型化版本是如此艰巨的原因,现在让我们回答“为什么不使用(旧的)类型化Actor”的问题。 首先,它们从未被设计为工具包的核心。它们建立在Akka提供的消息基础设施之上。请注意,由于这种消息基础设施,我们能够实现位置透明度和Akka的众所周知的性能。它们大量使用反射和JDK代理将方法转换为消息发送,并从消息接收者中翻译回来。这非常昂贵(时间上),与普通的Akka Actors相比,性能下降了约10倍。请参见下面的“乒乓”基准测试(使用两种风格实现,发送方告诉Actor,Actor回复- 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中,并使用OpenJDK JMH工具通过sbt-jmh插件运行。

其次,使用抽象方法来处理分布式系统并不是一个好的方式(哦,我还记得RMI……让我们不要再去那里了)。使用这种“看起来像方法”的方法会使您停止思考消息丢失、重新排序以及在分布式系统中可能发生的所有事情。它还鼓励(使“做错事情变得太容易”)使用诸如def getThing(id: Int): Thing这样的签名——这将生成阻塞代码——这对性能来说是可怕的!您真的希望保持异步和响应,这就是为什么在尝试与这些(基于代理的)类型化actor正确地工作时,您最终会得到大量的future。 最后,你基本上会失去一个主要的Actor能力。Actor可以执行的三个经典操作是1)发送消息2)启动子Actor3)根据接收到的消息更改自己的行为(请参见Carl Hewitt关于Actor Model的原始论文)。第三种能力用于优美地建模状态机。例如,您可以使用普通的akka actors说become(active)然后become(allowOnlyPrivileged),以在receive实现之间切换-使有限状态机实现(我们也有一个FSMs DSL)非常愉快。您无法在JDK代理的类型化Actor中很好地表达这一点,因为您无法更改公开方法的集合。一旦您开始思考和建模使用状态机,这是一个重大的缺点。 新的希望(第1集):请查看由Roland Kuhn编写的即将发布的akka-typed模块(预览版很快会包含在2.4版本中),我相信您会喜欢那里的类型安全性。而且,该实现最终将比当前的无类型actors更快(由于答案已经很长,在这里省略了实现细节 - 简短的版本:基本上我们将通过新的实现去除大量分配)。

我希望您会喜欢这个详尽的答案。请随时在此处或akka-user - 我们的官方邮件列表中提出后续问题。祝您编程愉快!


1
首先...感谢您提供这个很棒的答案。即使它更长,我也会继续阅读。 其次,我很想看到该页面的Java版本 =)。我不是Scala开发人员。 - Royi Freifeld
2
你是指 akka-typed 项目吗?我们还没有将它移植到 Java 上,但是肯定会的(!)。我认为它可能会包含在2.4版本中... 让我们拭目以待 :-) - Konrad 'ktoso' Malawski
非常好的解释,但是对于一些框架来说,它们使用类型化的Actor提供反应式系统给低级别开发人员,即使不了解Akka也很有用。作为一名经验丰富的开发者,我也不会考虑使用类型化的Actor,但对于那些没有动力去学习Akka并且只想保持舒适区域的开发者群体来说,让他们使用这些功能也是一个很大的优势。 - paul

0
Typed Actors 为您提供了一个在领域术语中定义的静态契约——您可以为它们命名消息(这些消息将被委托给底层实现并异步执行),这些操作在您的领域中是有意义的,避免了您自己使用反射(TypedActors 在幕后使用 JDK 代理,因此仍然存在反射,但您不必担心它,并且在传递给活动对象/类型化演员的参数和返回类型方面获得了类型检查。文档 对此非常清楚,但我知道对于那些新手来说,额外的示例总是有帮助的,所以如果您仍然对区别感到困惑,请随时提出其他问题/评论。

谢谢您的回答。我对文档中提出的最佳实践感到困惑。我不会实现适用于每个可能消息的软件。除此之外,Java不能使用与Scala相同的模式匹配。那么,为什么我不应该使用TypedActors作为我的Actor而不是UntypedActors?这对我来说毫无意义... - Royi Freifeld

0

但是你们是否意识到,有很多公司并没有专业的开发人员,但却拥有大规模水平扩展的基础设施,因此性能并不总是最好的“选择”,而是要具有响应性、消息驱动、弹性和韧性,现在我们有了类型化的演员,被那些不知道Akka或反应式编程的开发人员使用。

不要误会,我在日常工作中使用纯Akka typed,但对于交付团队,我们有这个框架使用类型化的演员,我们的消费者使用POJO,而不知道他们正在编写反应式系统。这是一个很棒的特性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接