【问题标题】:Why are messages received by an actor unordered?为什么演员收到的消息是无序的?
【发布时间】:2011-04-22 03:26:42
【问题描述】:

我一直在研究 Actor 模型(特别是 Scala 中的实现),但我不明白为什么要求消息以无特定顺序到达。

似乎至少有一些优雅的、基于参与者的并发问题解决方案,只要消息按顺序到达(例如生产者-消费者变体、延迟数据库写入、并发安全缓存),这些解决方案就可以工作。

那么为什么actor消息不按顺序到达呢?是为了允许有效的实施,还是为了防止在订购消息时出现某种死锁?

【问题讨论】:

标签: scala concurrency actor


【解决方案1】:

我的印象是,如果两个线程向一个actor a 发送一条消息,并不能特别保证哪个actor 会先收到。但是如果你的代码看起来像

a ! "one"
a ! "two"

那么a 将始终在"two" 之前获得"one"(尽管谁知道其他线程之间可能会出现什么)。

因此,我认为消息到达的顺序根本不是特定的。来自一个线程中的多条消息(据我从代码或经验中得知)将按顺序到达。

【讨论】:

  • @Viktor - 希望我对 Akka、Lift 和 Scalaz 也是正确的。将消息放入集合或堆栈似乎并不正确!
  • 不过有一个例外 - 优先消息队列。
【解决方案2】:

我不知道 Scala 的 Actors(至少在标准库中的那些 - 还有 Akka、Lift 和 Scalaz 的 Actors 实现)选择该特定实现的原因。可能是 Erlang 自身限制的副本——但没有保证两个单线程之间的通信。或者也许也有这样的保证——我希望 Phillip Haller 在这里发表评论。

但是,我确实质疑您关于并发问题的陈述。在研究异步分布式算法时,一个基本原则是你不能保证消息接收的任何顺序

引用 Hagit Attiya 和 Jennifer Welch 的 Distributed Computing: Fundamentals, Simulation and Advanced Topics

如果系统持续时间没有固定上限,则称该系统为异步系统 需要多少时间才能传递一条消息或连续之间经过多少时间 处理器的步骤。

actor 模型是异步的。这使它能够在分布式硬件上工作——无论是通过网络通信的不同计算机,还是系统上不提供同步保证的不同处理器。

此外,即使是多核处理器上的多线程模型也大多是异步的,支持同步的原语非常昂贵。

所以这个问题的简单答案可能是:

不保证消息按顺序到达,因为这是异步系统的潜在限制,这是参与者使用的基本计算模型。

这个模型是我们在任何通过 TCP/IP 分布的系统上实际拥有的模型,并且在 i386/x64 多核/多处理器硬件上效率最高。

【讨论】:

  • 丹尼尔,你总是切中要害,把它说得这么好。
【解决方案3】:

以下简单示例显示消息乱序到达一个非常简单的参与者:

import scala.actors._
import scala.actors.Actor._
import scala.collection.mutable._

val adder = actor {
  loop {
    react {
      case x: Int => println(" Computing " + x); reply(x+2)
      case Exit => println("Exiting"); exit
    }
  }
}

actor {
  for (i <- 1 to 5) {
    println("Sending " + i)
    adder !! (i, { case answer => println("Computed " + i + " -> " + answer) })
  }

  println("Sending Exit")
  adder !! Exit
}

这是在带有 Sun JDK 1.6.0u25 的 64 位 Windows 上使用 Scala 2.9.0 final 运行上述代码的输出:

Sending 1
Sending 2
Sending 3
Sending 4
Sending 5
Sending Exit
 Computing 1
Computed 1 -> 3
 Computing 4
Computed 4 -> 6
 Computing 3
Computed 3 -> 5
Exiting

【讨论】:

  • 非常有趣。我可以使用上面的代码重现此行为,但如果删除了期货的使用(通过将运算符“!!”替换为“!”),那么我运行的测试都显示了正在按顺序处理的消息。跨度>
【解决方案4】:

你会选择什么顺序?应该是发送时还是收到时?我们是否应该在对邮件进行排序时冻结整个邮箱?想象一下对一个大且几乎已满的邮箱进行排序,这不会在队列上设置任意锁吗?我认为消息没有按顺序到达,因为没有保证的方式来执行这样的命令。我们在网络和处理器之间存在延迟。

我们不知道消息来自哪里,只知道它们已经到达。那么这个怎么样,我们保证我们没有订购,甚至不考虑订购。不必想出一些令人印象深刻的逻辑来保持事物井井有条,同时尽可能保持无争用,我们可以专注于保持尽可能无争用。

对此,其他人的答案可能比我更好。

编辑:

现在我已经有时间睡觉了,我认为这是一个规定,可以创建一个更有活力的 Actor 生态系统。因此,为什么要限制线程池中的一个 Actor 或一个线程或线程的部分所有权?如果有人想要一个 Actor 来获取尽可能多的线程来处理其邮箱中尽可能多的消息呢?

如果您事先规定消息必须按照它们进行的顺序完成,您将永远无法允许这样做。 Actor 可以分配分钟多个线程来处理邮箱中的消息,而您将无法控制首先处理哪条消息。

呸,当你睡觉时,你的梦对你的思想有何影响。

【讨论】:

  • 我不是在谈论分布式演员,必然。为简单起见,假设它们都在同一个过程中。而且我认为将邮箱视为队列并不是特别随意,即消息按照添加到邮箱的顺序进行处理...
  • @Bill 但是,如果您正在编写一个库,如何强制要求消息仅来自同一台计算机而不是网络?
  • @wheaties:我认为你误解了这个问题。问题不在于对从任意客户端收到的消息进行排序。它是关于保持或不保持从同一客户端发送的消息的顺序,因为这是我们可以而且应该假设消息以 FIFO 方式处理的唯一情况。对于大多数应用程序来说,这是必不可少的,用户无论如何都必须实现它。 --> 下一条评论继续
  • 此外,将消息添加到队列(以保持检索顺序)远不能与消息排序相比。它与将新消息放入无序集合或其他任何东西一样努力。无论如何,您必须在多线程环境中同步对集合或队列的操作。因此,我希望 Rex Kerr 是正确的,他说 Scalas 演员已经保持了来自同一个客户端的传入消息的顺序,尽管比尔的问题表明它没有。
  • 如果同一个 Actor 一次处理多个消息,那么它就不再是一个 Actor。
猜你喜欢
  • 2013-11-29
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 2015-06-19
  • 2012-10-31
  • 1970-01-01
  • 2011-12-05
  • 2013-01-30
相关资源
最近更新 更多