单子和演员模型

8
我一直在尝试寻找有关何时应优先使用单子而不是演员(在并发情况下)的讨论,但我没有找到任何相关信息。特别是,我想知道使用响应式扩展(LINQ to Events)与F#的MailboxProcessor之间的区别。请提供示例以及您可能拥有的任何哲学推理。
更新: 为了更好地理解,响应式扩展以IObservable/IObserver的形式实现了连续单子。我并不一定要使用F#,只是F#通过MailboxProcessor<'T>在.NET语言中提供了一个具体的“演员模型”。
我想要理解的是何时为了并发目的使用单子(在这种情况下是连续单子),而不是演员模型。单子(据我所知)不引入状态,而演员则具有自己的内部状态,根据需要进行修改以提供受保护的访问。
我看过许多使用Rx和node.js(CPS,不是真正的连续单子)与F#的MailboxProcessor和Scala的Akka框架的示例。我只是不知道为什么会选择一个而不是另一个。

1
这对你来说可能完全没有用,因为我不懂f#,也不真正理解你的问题从何而来,但是我在Haskell中编写了一个Actor模型实现,它利用了Monad Stack(Actor计算是Reader/IO Monad):http://hackage.haskell.org/packages/archive/simple-actors/0.1.0/doc/html/Control-Concurrent-Actors.html - jberryman
Phil Trelford(http://twitter.com/ptrelford)还创建了一个使用actors的Rx实现(http://minirx.codeplex.com/),因此根据您正在做什么,您可以使用monads实现actors或使用actors实现monads。 - user29439
1
又是一篇“可能对你没有用”的文章。有人曾指出,Rx 的主要目的不是引入并发,而是解决并发问题。虽然人们可能认为 F# 代理是引入并发的适当方式。 - David Grenier
4个回答

4
我不确定问题的措辞是否有意义-有许多不同的单子(例如身份单子、列表单子、选项单子等),其中大部分与并发无关。此外,了解您正在处理的特定情况将非常有帮助-“并发”是一个模糊的主题。根据您想要实现的目标,F#的async工作流(建立在Async单子上)可能是最好的选择。
如果您正在使用F#,我建议不要直接使用LINQ-to-anything,因为当通过F#访问这些库时会感到非常陌生。但是,您可以创建愉悦的F#包装器(例如现有的SeqObservable模块)。此外,对于单调类型,您可以创建一个计算表达式生成器(例如,您可以使用反应扩展创建一个生成器,使您能够使用计算表达式来构建和组合IObservables)。

我熟悉这些选项。我很好奇为什么您要在某些情况下选择一个而不是另一个。也许这是个人偏好的问题,但我想尝试更好地理解。如果您想查看一些 F# 到 Rx 的包装器,请访问我的 bitbucket 存储库:http://bitbucket.org/riles01/fsharp.reactive - user29439
1
看起来你正在比较一个具有可以独立于计算填充的后备存储器(MbP)和一个没有后备存储器的情况(Seq/Observable)。这些是非常不同的情况,将取决于应用程序。 - 7sharp9

1

请原谅我的新手-ness,因为我正在学习 F#。

我很惊奇地看到了 RX 的使用,取代了 MailboxProcessor,如果您有任何相关材料的链接,请提供一下。

在我有限的理解中;我会选择在我的代码中选择 MbP,因为在 F# 中设置事件有点混乱(从我从这篇文章MSDN中获取的信息可以得出)。而且你需要事件来钩入 RX 对吧?

而对于 MbP,我所需要的只是一个消息区分联合、我希望在接收到某个消息时执行的函数列表。以及处理它的邮箱处理器。

所有这些看起来在代码中非常整洁。我可以将我的 MbP 组合在一个模块中,然后我的“对象”模块看起来像:

  • 记录
  • 消息 DU
  • 包装器,带有一些获取器和设置器,将数据发布到 MbP

对我来说,这比我根据我链接的那篇 MSDN 文章所描述的写代码事件要整洁得多。

虽然我只是一个初级的 F# 程序员,所以我的估计可能相差甚远,这更多是一种外观和感觉的选择,而不是适用性的选择(因为我还没有资格作出那样的判断)。

根据你如何暴露你的事件,你可以仅声明一个事件并将其作为 IObservable 返回,然后在 Subscribe 方法中调用 Trigger() 方法,因此我认为事件并不那么糟糕。 MbP 有自己的要求。 - user29439
@jdoig,您所描述的基本上是MbP使用的标准模式。这里有各种示例:http://fssnip.net/tags/Agent - 7sharp9
请注意,您甚至可以从各种内置的静态方法生成可观察对象。我认为您永远不需要设置任何事件,代码将更符合惯用/功能性Rx。 - David Grenier

1

你是否接受来自Scala世界的答案?

如果您正在寻找“纯函数式替代actor模型”,请参阅Paul Chiusano博客中的这篇精彩文章

pchiusano.blogspot.ro/2010/01/actors-are-not-good-concurrency-model.html (存档在此处:http://archive.is/NxNLc

以下是一些参考资料:

http://noelwelsh.com/programming/2013/03/04/why-i-dont-like-akka-actors/

演员不作曲 Akka的演员没有有用的类型 类型系统是我们使用Scala的原因。

https://opencredo.com/akka-typed/

很遗憾,当前的API存在一些缺点,这些缺点在很大程度上与缺乏类型安全有关。

http://doc.akka.io/docs/akka/snapshot/scala/typed.html

这个项目的状态和与Akka Actors的关系 Akka Typed是多年研究和先前尝试(包括2.2.x系列中的Typed Channels)的结果,并且正在朝着稳定方向发展,但成熟一个对Akka核心概念如此深刻的改变需要很长时间

这个的一个副作用是,现在可以在不必将行为打包到Actor中的情况下对其进行隔离测试,测试可以完全同步运行,而不必担心超时和虚假失败。另一个副作用是,行为可以很好地组合和装饰

使用价格合理的单子构建可组合的应用程序架构

"Heather Miller提出的“函数传递风格”概念可能是分布式函数编程模型的关键。"
"更新于12/2018:现在我们可以使用Aecor,它提供了以下方法:"
"使用函数式编程模型实现业务域逻辑,并使用基于Akka的运行时。"
"“行为属于领域层,运行时位于基础架构层。”"
"来源:https://pavkin.ru/aecor-part-3/,http://aecor.io"
"SF Scala: Heather Miller, Function-Passing Style, A New Model for Distributed Programming"
"https://pavkin.ru/aecor-part-3/, http://aecor.io"

0

我将回答自己的问题并说您应该同时使用两者。这是基于Don Syme's post。MbP使用Async计算来完成其工作,而Async是一个线程感知的继续单子。看起来您可以仅使用它来进行某些用途,但是MbP绝对需要它。

我不太喜欢这个答案,如果有人能给出更好的解释何时使用每个选项,我会很高兴。

更新:

请参见MiniRx,它现在是FSharpx的一部分,用于实现使用MailboxProcessor实现的Rx样式单子。由于MailboxProcessor本身是使用async单子实现的,因此这些部件确实可以一起使用。它们只是不同的抽象手段。


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