актеры против нормальных объектов - PullRequest
1 голос
/ 24 января 2020

Из книги о реактивных приложениях с использованием актеров akka:

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

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

1 Ответ

0 голосов
/ 24 января 2020

(для "объекта" вы должны обычно читать это как "объект, как реализовано и используется в большинстве языков ОО")

Я не думаю, что это точно, чтобы сказать, что "объекты потребляют только потоки когда его просят что-то сделать ": точнее сказать, что потоки потребляют объекты, а не наоборот. Но каким бы образом мы ни рассматривали стрелку потребления, важно отметить, что она не ограничена: объект может потреблять / потребляться произвольным числом потоков в данный момент времени, а поток может потреблять / потребляться произвольным количеством объектов в данном моменте. момент времени.

Рассмотрим следующий код Scala:

class A(private var b: B) {
  def doSomethingWithB(): Unit = {
    b.doSomething()
  }
}

class B(private var x: Int) {
  def doSomething(): Unit = {
    x += 1
  }
}

def foo(a: A): Unit = {
  // yadda yadda yadda
  a.doSomethingWithB()
}

Поток входит в foo и потребляет a, вызывая doSomethingWithB. Все еще потребляя a, он потребляет a.b, вызывая doSomething. Он прекращает потребление a.b, а затем прекращает потребление a.

Для системы акторов оба из этих 1: N кардиналов равны 1: самое большее один.

Очевидно, мы можем сделать реализацию объекта имеющей актерские ограничения: если каждое публиковать c средство использования объекта требует получения блокировки, то не более чем один поток может потреблять / быть поглощенным объектом. Между тем, для второго ограничения мы можем ограничить это, например:

// simplified without references to things like ExecutionContexts
class A(...) {
  def doSomethingWithB(): Future[Unit] = {
    Future.successful(b).flatMap(_.doSomething())
  }
}

class B(...) {
  def doSomething(): Future[Unit] = {
    x += 1
    Future.successful(())
  }
}

def foo(a: A): Future[Unit] = {
  a.doSomethingWithB()
}

Теперь при вызове doSomethingWithB вызывающий поток (в общем) не потребляет a.b: потребление a.b (путем вызова doSomething) происходит в другом потоке или, возможно, (если исходный поток является просто рабочим потоком в пуле потоков) в вызывающем потоке после его возврата из foo.

Излишне говорить, что это довольно неестественный стиль в ОО (и Scala, возможно, является языком, где это наиболее эргономично c, в основном потому, что реализация стандартной библиотеки Future очень похожа на реализацию системы актера).

...