演员模型不是一种反模式吗,因为即发即弃的风格迫使演员记住一个状态?

Posted

技术标签:

【中文标题】演员模型不是一种反模式吗,因为即发即弃的风格迫使演员记住一个状态?【英文标题】:Is the actor model not an anti-pattern, as the fire-and-forget style forces actors to remember a state? 【发布时间】:2017-02-28 18:59:09 【问题描述】:

在学习 Scala 时,我学到的第一件事就是每个函数都会返回一些东西。没有“void”-function/method,例如在 Java 中。因此,许多 Scala 函数在数学上都是真正的函数,并且对象可以在很大程度上保持无状态。

现在我了解到,actor 模型是 Scala 等函数式语言中非常流行的模型。然而,actor 提倡一种即发即弃的编程风格,调用者通常不希望被调用者直接回复消息(使用“询问”/“?”方法时除外)。因此,actor 需要记住某种状态。

假设 Actor 模型更像是可伸缩性和可维护性之间的权衡(由于其状态性),我是否正确,有时甚至可以被视为反模式?

【问题讨论】:

Unit 是否或多或少对应于 Java 的 void " 没有“void”函数/方法,例如在 Java 中。因此许多 Scala 函数在数学上是真正的函数,并且对象可以在很大程度上保持无状态。第二点不是从第一点得出的。无状态对象和真正的函数与“void”类型的缺失毫无关系(无论如何,正如@rethab 指出的那样,Unit 是 Scala 的 void)。 嗯 iirc ask 没有阻塞。它有一个超时,但它没有阻塞。 【参考方案1】:

是的,您基本上是对的(当您说可扩展性与可维护性时,我不太确定您的想法是什么)。

Actor 在 Scala 中很受欢迎,因为 Akka(可能反过来又很受欢迎,因为它得到了 Lightbend 的支持)。然而,在函数式编程世界中,演员并非普遍流行(尽管我正在考虑的所有语言都存在实现)。下面是我对另外两个 FP 语言社区的大大简化的印象(因此请务必加盐),这两个社区都比 Scala 更少使用 actor(远?)。

Haskell 社区倾向于使用STM/channels(通常在STM context 中)。直截了当的MVars 也经常被使用。 Clojure 社区有时会吹捧自己的内置 STM 版本,但它的旗舰并发模型实际上是 core.async,这又是它的核心渠道。

作为旁观的 STM,频道和演员都可以相互叠加;将它们进行比较,就好像它们是相互排斥的方法一样,有点奇怪。在实践中,虽然很少看到它们全部串联使用。

Actor 确实涉及状态(在 Akka 裙子类型安全的情况下),因此非常具有表现力,并且几乎可以在并发方面做任何事情。通过这种方式,它们类似于副作用函数,比纯函数更具表现力。事实上,演员在某种程度上是面向对象的纯粹本质,具有所有优点和缺点。

因此,Scala 社区的 sizable chunk 会说是的,如果大多数时候当您遇到并发问题时,您使用的是演员,那可能是一种反模式。

如果可以的话,尽量不使用Futures 或scalaz.concurrent.Tasks。 In return for less expressiveness you get more composability. 如果您的问题自然而然地适用于单一的全局状态(例如,以您想要强制执行的全局不变量的形式),请考虑 STM。在Scala社区中,虽然有an STM library存在,但我的印象是STM一般都是用actors来模拟的。 如果您的并发问题主要涉及流式传输多个数据源,请考虑使用 Scala 的 streaming libraries 之一。

【讨论】:

【参考方案2】:

Actor 是工具箱中专门用于处理和分发状态的工具。所以是的,他们应该有状态——如果他们没有,那么你就可以使用 Futures。

但是请注意,Actor(至少是 Akka Actor)处理 distribution(在多个节点上透明地运行位置),这两个 Futures 的功能都无法做到。 Actor 的并发方面是它们处理更复杂情况的结果 - 网络。从这个意义上说,Actor 通过使远程案例成为一流的,将远程案例与本地案例统一起来。事实证明,如果您想要可靠、弹性和快速的系统,网络消息传递正是您可以依靠和构建的。

希望这能回答您问题的“大局”部分。

【讨论】:

以上是关于演员模型不是一种反模式吗,因为即发即弃的风格迫使演员记住一个状态?的主要内容,如果未能解决你的问题,请参考以下文章

异步/等待有/无等待(即发即弃)

对 api 服务器的多个异步请求(即发即弃)

如何实现从一个进程到另一个进程的即发即弃消息传递?

触发单向 ajax 调用

如何以 Fire-And-Forget 的形式调用委托调用

Redis学习之发布与订阅机制