简体   繁体   English

为什么演员收到的消息是无序的?

[英]Why are messages received by an actor unordered?

I've been studying the actor model (specifically the implementation in Scala) but I can't understand why there's a requirement that messages arrive in no particular order. 我一直在研究actor模型(特别是Scala中的实现)但我无法理解为什么要求消息没有按特定顺序到达。

It seems like there are at least some elegant, actor-based solutions to concurrency problems that would work if only the messages arrived in order (eg producer-consumer variants, deferred database writes, concurrency-safe caches). 似乎至少有一些优雅的,基于actor的并发问题解决方案,只有消息按顺序到达时才会起作用(例如,生产者 - 消费者变体,延迟数据库写入,并发安全缓存)。

So why don't actor messages arrive in order? 那么为什么演员的消息没有按顺序到达? Is it to permit efficient implementation or maybe to prevent some kind of deadlock that would arise when messages are ordered? 它是允许有效实现还是可以防止在订购消息时出现某种死锁?

My impression is that if two threads send a message to an actor a , there is no particular guarantee about which will be received by the actor first. 我的印象是,如果两个线程向一个演员a发送一条消息,则没有特别保证演员首先接收到哪一个。 But if you have code that looks like 但是如果你有代码看起来像

a ! "one"
a ! "two"

then a will always get "one" before "two" (though who knows what else might have arrived in between from other threads). 那么a总是会在"two" "one"之前得到"one" (虽然谁知道其他线程之间可能还有什么)。

Thus, I don't think it is the case that messages arrive in no particular order at all. 因此,我不认为消息根本没有特定的顺序。 Multiple messages from within one thread will (as far as I can tell from the code or from experience) arrive in order. 来自一个线程内的多条消息(根据我从代码或经验中可以看出)将按顺序到达。

I'm not privy to the reasons why Scala's Actors (those in the standard library, at any rate -- there are also Akka, Lift and Scalaz implementations of Actors) chose that particular implementation. 我不知道为什么Scala的Actors(标准库中的那些,无论如何 - 还有Aka的Akka,Lift和Scalaz实现)选择了这个特定的实现。 Probably as a copy of Erlang's own restrictions -- but without the guarantees for communication between two single threads. 可能是Erlang自身限制的副本 - 但没有两个单线程之间通信的保证。 Or maybe with that guarantee as well -- I wish Phillip Haller was here to comment. 或许也有这种保证 - 我希望Phillip Haller在这里发表评论。

BUT, I do question your statement about concurrency problems. 但是,我确实质疑你关于并发问题的陈述。 When studying asynchronous distributed algorithms, a basic tenet is that you can't guarantee any ordering of message receipt. 在研究异步分布式算法时,一个基本原则是您不能保证任何消息接收顺序

To quote Distributed Computing: Fundamentals, Simulation and Advanced Topics , by Hagit Attiya and Jennifer Welch, 引用Hagit Attiya和Jennifer Welch的分布式计算:基础,模拟和高级主题

A system is said to be asynchronous if there is no fixed upper bound on how long it takes for a message to be delivered or how much time elapses between consecutive steps of a processor. 如果对于消息传递所花费的时间或处理器的连续步骤之间经过了多长时间没有固定的上限,则称系统是异步的。

The actor model is an asynchronous one. actor模型是异步模型。 That enables it to work over distributed hardware -- be it different computers communicating through a network, or different processors on a system that does not provide synchronous guarantees. 这使它能够在分布式硬件上工作 - 无论是通过网络进行通信的不同计算机,还是不提供同步保证的系统上的不同处理器。

Furthermore, even the multi-threading model on a multi-core processor is mostly asynchronous, with the primitives that enable synchronism being extremely expensive. 此外,甚至多核处理器上的多线程模型也大多是异步的,其中同步的原语非常昂贵。

So a simple answer to the question might be: 所以问题的简单答案可能是:

Messages are not guaranteed to arrive in order because that's an underlying limitation of asynchronous systems, which is the basic model of computation used by actors. 消息不能保证按顺序到达,因为这是异步系统的基本限制,异步系统是actor使用的基本计算模型。

This model is the one we actually have on any system distributed over TCP/IP, and the most efficient over i386/x64 multicore/multiprocessor hardware. 这个模型是我们在任何通过TCP / IP分布的系统上实际拥有的模型,也是i386 / x64多核/多处理器硬件上最高效的模型。

The following simple example shows messages arriving out of order to a very simple actor: 以下简单示例显示了按顺序到达非常简单的actor的消息:

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
}

Here is the output from one run of the above code with Scala 2.9.0 final on Windows 64-bit with Sun JDK 1.6.0u25: 以下是使用Sun JDK 1.6.0u25在Windows 64位上使用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

What order would you choose? 你会选择什么样的订单? Should it be by when they were sent or when they were recieved? 应该是在他们被送去还是收到他们的时候? Should we freeze the entire mailbox whilst we sort the messages? 在我们对邮件进行排序时,我们应该冻结整个邮箱吗? Imagine sorting a large and nearly full mailbox, wouldn't that put an arbitrary lock on the queue? 想象一下,对一个大而近乎完整的邮箱进行排序,是否会对队列进行任意锁定? I think the messages don't arrive in order because there is no guaranteed way to enforce such an order. 我认为消息没有按顺序到达,因为没有保证执行此类订单的方法。 We have latency in networks and between processors. 我们在网络和处理器之间存在延迟。

We have no idea where the messages are coming from, only that they have arrived. 我们不知道消息来自哪里,只知道它们已经到达。 So how about this, we make the guarantee that we have no ordering and don't even try to think about ordering. 那么这个怎么样,我们保证我们没有订购,甚至没有考虑订购。 Instead of having to come up with some impressive logic to keep things organized while remaining as contention-free as possible we can just focus on keeping things as contention-free as possible. 我们可以专注于尽可能保持争用,而不是必须提出一些令人印象深刻的逻辑来保持组织有序,同时尽可能保持无争用。

Someone else probably has an even better answer than I on this. 其他人可能比我对此有更好的答案。

Edit: 编辑:

Now that I've had time to sleep on it, I think it's a stipulation that allows for a much more vibrant Actor ecosystem to be created. 现在我已经有时间睡觉了,我认为这是一个规定,允许创建一个更有活力的Actor生态系统。 Hence, why restrict one Actor or one thread or partial ownership of a thread from a thread pool? 因此,为什么要从线程池中限制一个Actor或一个线程或线程的部分所有权? What if someone wanted to have an Actor which could grab as many threads as possible to process as many messages in its mailbox as it could? 如果有人希望拥有一个可以尽可能多地获取线程的Actor来尽可能多地处理其邮箱中的邮件,该怎么办?

If you made the stipulation up front that messages had to be done in the order they proceeded you'd never be able to allow for this. 如果您事先做出规定,消息必须按照他们继续进行的顺序完成,那么您永远无法允许这样做。 The minute multiple threads could be assigned by an Actor to process messages within the mailbox you'd be in the situation whereby you had no control over which message was processed first. 可以由Actor分配多个线程来处理邮箱中的邮件,您将无法控制首先处理哪个邮件。

Phew, what your dreams say about your mind as you sleep. Phew,你的梦想在你睡觉时对你的思想所说的话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM