Почему сообщения, полученные актером, неупорядочены?

Я изучаю модель актера (в частности, реализацию в Scala), но я не понимаю, почему существует требование, чтобы сообщения не поступали в определенном порядке.

Похоже, существуют, по крайней мере, некоторые изящные, основанные на актерах решения проблем concurrency, которые будут работать, если будут поступать только сообщения (например, варианты-производители-потребители, отложенные записи базы данных, concurrency -серверные кеши).

Итак, почему сообщения актера не поступают по порядку? Должно ли это позволить эффективную реализацию или, возможно, предотвратить какой-то тупик, который возникнет при заказе сообщений?

Ответ 1

У меня сложилось впечатление, что если два потока отправляют сообщение актеру a, нет никакой конкретной гарантии, по которой сначала будет получен актер. Но если у вас есть код, который выглядит как

a ! "one"
a ! "two"

то a всегда будет получать "one" до "two" (хотя кто знает, что еще могло произойти между другими потоками).

Таким образом, я не думаю, что это так, что сообщения поступают совсем не в порядке. Несколько сообщений из одного потока будут (насколько я могу судить по коду или опыту) приходить в порядок.

Ответ 2

Я не отношусь к причинам, почему Scala Актеры (в стандартной библиотеке, во всяком случае, есть также актеры Akka, Lift и Scalaz), выбрали именно эту реализацию. Вероятно, в качестве копии собственных прав Эрланга, но без гарантий для связи между двумя отдельными потоками. Или, может быть, с этой гарантией - я хочу, чтобы Филлип Халлер был здесь, чтобы прокомментировать.

НО, я задаю ваше утверждение о проблемах concurrency. При изучении асинхронных распределенных алгоритмов основной принцип заключается в том, что вы не можете гарантировать порядок доставки сообщений.

Чтобы процитировать Распределенные вычисления: основы, моделирование и продвинутые темы, Хагит Аттия и Дженнифер Уэлч,

Система называется асинхронной, если нет фиксированной верхней границы того, как долго она требует, чтобы сообщение было доставлено или сколько времени прошло между последовательными шагов процессора.

Модель актера является асинхронной. Это позволяет работать с распределенным оборудованием - будь то разные компьютеры, обменивающиеся через сеть или разные процессоры в системе, которая не обеспечивает синхронных гарантий.

Кроме того, даже многопоточная модель на многоядерном процессоре в основном асинхронна, причем примитивы, которые позволяют синхронизировать чрезвычайно дорого.

Таким образом, простой ответ на вопрос может быть следующим:

Не гарантируется получение сообщений, поскольку это основное ограничение асинхронных систем, которое является базовой моделью вычислений, используемой субъектами.

Эта модель - та, которая у нас есть на любой системе, распределенной по 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
}

Вот результат одного запуска вышеуказанного кода с Scala 2.9.0 final на Windows 64-bit с Sun JDK 1.6.0u25:

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

Какой порядок вы бы выбрали? Должны ли они быть отправлены или когда они были получены? Должны ли мы заморозить весь почтовый ящик, пока мы сортируем сообщения? Представьте себе, что сортировка большого и почти полного почтового ящика не приведет к произвольной блокировке очереди? Я думаю, что сообщения не поступают по порядку, потому что нет гарантированного способа принудительного исполнения такого заказа. У нас есть латентность в сетях и между процессорами.

Мы понятия не имеем, откуда идут сообщения, только то, что они прибыли. Итак, как насчет этого, мы гарантируем, что у нас нет заказов, и даже не пытайтесь думать о заказе. Вместо того, чтобы придумывать какую-то внушительную логику, чтобы держать вещи организованными, оставаясь как можно более свободными от конкуренции, мы можем просто сосредоточиться на том, чтобы держать все как можно свободнее.

У кого-то, возможно, есть еще лучший ответ, чем я.

Edit:

Теперь, когда я успел заснуть на этом, я думаю, что это условие, которое позволяет создать гораздо более яркую экосистему Актера. Следовательно, зачем ограничивать один Актер или один поток или частичное владение нитью из пула потоков? Что делать, если кто-то хочет иметь актера, который мог бы захватить как можно больше потоков для обработки как можно большего количества сообщений в своем почтовом ящике?

Если вы указали заранее, что сообщения должны быть выполнены в том порядке, в котором они выполнялись, вы никогда не сможете этого разрешить. Минуту несколько потоков могут быть назначены Актером для обработки сообщений в почтовом ящике, в котором вы были бы в ситуации, когда у вас не было контроля над тем, какое сообщение было обработано в первую очередь.

Фу, что твои мечты говорят о твоем разуме, когда ты спишь.