17

我在第 379 页的 Expert F# 副本中注意到以下评论:

传递和处理消息

共享内存并发消息传递并发之间经常存在区别 。前者在本地机器上通常更有效,本章后面的“使用共享内存并发”部分会介绍。后者适用于没有共享内存的系统,例如分布式系统,也可用于避免与共享内存相关的性能问题。

我对没有共享内存的进程之间的消息传递并发感兴趣。Expert F# 中的所有示例以及 Internet 上演示如何使用 MailboxProcessor 的所有示例都包含此代码的一些变体:

let counter =
    MailboxProcessor.Start(fun inbox ->
        let rec loop n =
            async {
                do printfn "n = %d, waiting... " n
                let! msg = inbox.Receive()
                match msg with
                    | -1 ->
                        do printfn "'Til the bitter end..."
                        return ()
                    | n -> return! loop(n + msg)
            }
        loop 0)

counter.Post(20)
counter.Post(50)
counter.Post(-1) // kill mailbox

换句话说,您必须先在共享内存中处理 MailboxProcessor,然后才能将消息发布到其通道。据我所知,这不是 Erlang 风格的并发,因为您只能在同一进程中将消息发布到 MailboxProcessors(注意:进程,而不是线程)。

一个进程中的一个 MailboxProcessor 是否可以将消息发送到另一个 MailboxProcessor 进程?如果是这样,你能提供一个样本吗?

4

3 回答 3

8

我认为您对术语有些困惑。Erlang 进程不一定直接对应于 OS 进程。一个给定的 OS 进程可以有多个 Erlang 进程(通常是这样),就像你的进程有多个线程一样。如果您想在多个操作系统进程之间进行通信,您可能需要查看System.Runtime.Remoting.Channels.Ipc。可以想象,可以围绕这些 API 创建 MailboxProcessor 样式的包装器。

于 2009-02-02T03:37:38.987 回答
8

MailboxProcessor 和 AsyncReplyChannel 不提供与 Erlang 中的“pid bang”(Pid !)操作相同的位置透明度。当然,这只有在分布式 Erlang 节点配置正确的情况下才有效,即名称、DNS、同步模块、cookie 等。OTP 中有一些特性可以使这种管理更容易。当然,如果 Erlang 进程在同一个节点上,它就可以工作。但是,分布式 Erlang 存在一些问题。

“网络是安全的。” 内置的分布式 Erlang 机制假设网络是安全的。因此,当需要安全性时,使用代理 Erlang 进程的基于套接字的通信方法。

“网络可靠。” 使分布式 Erlang 工作的原因之一是它的错误处理理念,即进程是不可靠的,因此容错只能通过通信进程监视器来实现。OTP 编纂了模式(即主管)来实现这一理念。Erlang 中的可靠消息传递可以通过 Mnesia(一个分布式数据库)实现,就像在 RabbitMQ 中所做的那样,但您不能开箱即用。

最后,分布式通信从未如此简单。我们可以在 F# 中实现一个 AsynchWorker 来充当我们的代理并通过 AsynchReplyChannel.Send 与其通信。我们仍然需要考虑分布式计算的谬误。

最后,消息传递风格的并发并不意味着进程外通信。它确实意味着没有共享状态可以用锁来管理,因此是一个更简单、更不容易出错的并行计算模型。我认为这个素数筛是这种并发风格的一个很好的例子。F# 示例不像 Squeak 或 Erlang 实现那样美观,因为缺少用于消息传递的内置语法,但它可以工作。

于 2010-07-21T19:11:27.273 回答
1

也许这会做

使用 F# 代理 Map Reduce

我没有得到太多反馈,所以不确定它是否 100% 正确。如果您认为它不好,请告诉我。

感谢!

于 2011-02-08T16:51:29.507 回答