Akka's Actor与Erlang's Actor中消息顺序语义的后果



来自 class Coursera 上的响应式编程原理:

"如果一个参与者向同一目的地发送多条消息,它们将不会乱序到达(这是Akka特有的(。

演员 A 和 B

A 发送 B 消息 1A 发送 B 消息 2

B 将接收消息 1,然后接收消息 2

警告:我从来没有用过 Erlang 编程

我相信这个消息排序语义在 Erlang 中是不能保证的。这似乎是一个巨大的差异,会影响您可以使用应该是类似框架编写的不同类型的程序。

例如,在 Akka 中,您可以执行以下操作:

case class msg(x: Int)
case object report
class B extends Actor {
var i: Int = 0
def recieve = {
    case msg(x) => i = i + x
    case report => sender ! i
 }
}

然后你可以做

A 发送 B 消息(5(

A 发送 B 消息(6(

A 发送 B 报告//保证总和为 11

我的主要观点是,在 Erlang 中,您似乎无法保证返回的总和为 11。Erlang 是否阻止甚至禁止 Actor 包含任何可变状态?谁能详细说明在Scala的Akka与Erlang中可以用Actor编写和不能编写的不同类型的程序?

正如 Pascal 所说,两个进程之间的消息顺序是有保证的。在 Erlang 中,拥有某种"可变状态"的唯一方法是将其隐藏在 actor 后面。通常这样做:

loop(Sum) ->
    NewSum = receive Message of
        {msg, Number, Sender} -> add_and_reply(Sum, Number, Sender);
        _ -> Sum
    end,
    loop(NewSum).
add_and_reply(Sum, Number, Sender) ->
    NewSum = Sum + Number,
    Sender ! NewSum,
    NewSum.

这样,您就不会改变任何东西。您创建新状态并将其作为无休止递归的参数传递。运行循环的 Actor 确保所有调用都逐个提供服务,因为它一次只接受一条消息。

对我来说,Erlang 和 Akka 之间的主要区别在于抢占式调度。在 Erlang 中,你可以编写这样做的 actor:

loop(Foo) ->
    something_processor_consuming(),
    loop(Foo).

您的系统将正常工作。大多数语言,其中Actor是由库添加的,将转到此线程,它将永远运行,阻止一个CPU内核执行。Erlang 能够停止该线程,运行其他内容并返回到它,因此即使您搞砸了某些内容,它也能很好地运行。在此处阅读更多内容。在 Erlang 中,您可以从外部exit(Pid, kill)终止进程,它将立即终止。在 Akka 中,它将继续处理,直到它准备好接收下一条消息(您可以使用 Erlang 使用trap_exit标志进行模拟(。

Erlang 从一开始就考虑到了容错和软实时系统,因此 OTP 强调监督流程。例如,在 Scala 中,主管有机会在错误时恢复子级,而在 Erlang 中,子级在错误时崩溃,必须重新启动。这是因为假设,崩溃意味着糟糕的状态,我们不希望传播它。

答案是肯定的,这是有保证的:请参阅常见问题解答(它没有明确编写,但以已知顺序发送消息的唯一方法是从同一进程发送它们(

10.8  Is the order of message reception guaranteed?
Yes, but only within one process.
If there is a live process and you send it message A and then message B, it's guaranteed that if message B arrived, message A arrived before it.
On the other hand, imagine processes P, Q and R. P sends message A to Q, and then message B to R. There is no guarantee that A arrives before B. (Distributed Erlang would have a pretty tough time if this was required!)

是的,你可以保证这种情况——"Erlang消息"并不意味着"简单的UDP"。

A 可以向 B 发送"1,2,3,4,5",

它将按该顺序获得"1,2,3,4,5",无论 A 和 B 在集群中的哪个位置 - 考虑该语句的最后一部分的含义......

不能保证的是,相对于可能与 A 的并发消息流交错,从 C 到 B 的消息"a,b,c,d,e"到达 B 的顺序是什么。"1,2,a,b,c,3,4,5,d,e"与"1,2,3,4,5,a,b,c,d,e"或两个独立排序的消息流的任何其他交错交错一样。

最新更新