Я нашел в документах Akka:

При использовании будущих обратных вызовов, таких как onComplete, onSuccess и onFailure, внутри субъектов необходимо тщательно избегать закрытия ссылки на содержащего актора, т.е. не вызывать методы и не обращаться к изменяемому состоянию включающего субъекта из обратного вызова.

Значит ли это, что я всегда должен использовать future pipeTo self, а затем вызывать некоторые функции? Или я все еще могу использовать обратные вызовы с методом, тогда как мне избежать ошибок параллелизма?

13
user1078671 28 Май 2014 в 13:45

4 ответа

Лучший ответ

Это значит это:

class NotThreadSafeActor extends Actor {

  import context.dispatcher

  var counter = 0

  def receive = {
    case any =>
      counter = counter + 1
      Future {
        // do something else on a future
        Thread.sleep(2000)
      }.onComplete {
        _ => counter = counter + 1
      }
  }
}

В этом примере и метод приема актора, и метод onComplete Future изменяют изменяемую переменную counter. В этом игрушечном примере это легче увидеть, но вызов Future может быть вложенными методами, которые в равной степени захватывают изменяемую переменную.

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

12
sksamuel 28 Май 2014 в 09:58

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

4
drexin 28 Май 2014 в 09:54

Думаю, было бы упущением, если бы я не упомянул здесь, что сделал небольшую утилиту для обхода этого ограничения. Другими словами, мой ответ на ваш вопрос - нет, вам не следует использовать такой неудобный обходной путь, вы должны использовать https : //github.com/makoConstruct/RequestResponseActor

как это работает?

По сути, за фьючерсами и обещаниями он передает каждый запрос в Request(id:Int, content:Any), а когда он получает Response(id, result), он завершает будущее, соответствующее id, со значением result. Он также способен передавать сообщения об ошибках, и, насколько я могу судить, akka может регистрировать только таймауты запросов. RequestResponseActor предоставляет специальный неявный контекст выполнения для применения к обратным вызовам, прикрепленным к фьючерсам, ожидающим сообщения Response. Этот тупой контекст выполнения гарантирует, что они выполняются, пока обрабатывается ответное сообщение, тем самым гарантируя, что Актер имеет эксклюзивный доступ к своему состоянию при срабатывании будущих обратных вызовов.

0
Community 20 Июн 2020 в 09:12

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

https://github.com/Adeynack/ScalaLearning/tree/master/ActorThreadingTest/src/main/scala/david/ActorThreadingTest

Конечно, открыты для комментариев и предложений.

Будущее с актерами - тема, которая меня очень интересует.

0
Adeynack 15 Июн 2015 в 16:28