Я нашел в документах Akka:
При использовании будущих обратных вызовов, таких как onComplete, onSuccess и onFailure, внутри субъектов необходимо тщательно избегать закрытия ссылки на содержащего актора, т.е. не вызывать методы и не обращаться к изменяемому состоянию включающего субъекта из обратного вызова.
Значит ли это, что я всегда должен использовать future pipeTo self
, а затем вызывать некоторые функции? Или я все еще могу использовать обратные вызовы с методом, тогда как мне избежать ошибок параллелизма?
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
, таким образом давая вам состояние гонки . Что, в первую очередь, отрицает суть актера.
Да, вы должны отправить сообщение окружающему актору, если обратный вызов изменяет внутреннее состояние актора. Это самый простой (и предпочтительный) способ избежать гонок.
Думаю, было бы упущением, если бы я не упомянул здесь, что сделал небольшую утилиту для обхода этого ограничения. Другими словами, мой ответ на ваш вопрос - нет, вам не следует использовать такой неудобный обходной путь, вы должны использовать https : //github.com/makoConstruct/RequestResponseActor
как это работает?
По сути, за фьючерсами и обещаниями он передает каждый запрос в
Request(id:Int, content:Any)
, а когда он получаетResponse(id, result)
, он завершает будущее, соответствующее id, со значениемresult
. Он также способен передавать сообщения об ошибках, и, насколько я могу судить, akka может регистрировать только таймауты запросов. RequestResponseActor предоставляет специальный неявный контекст выполнения для применения к обратным вызовам, прикрепленным к фьючерсам, ожидающим сообщения Response. Этот тупой контекст выполнения гарантирует, что они выполняются, пока обрабатывается ответное сообщение, тем самым гарантируя, что Актер имеет эксклюзивный доступ к своему состоянию при срабатывании будущих обратных вызовов.
Может это поможет. Это эксперимент, который я провел, и результаты его довольно убедительны ... однако это все еще эксперимент, так что не воспринимайте это как экспертизу.
Конечно, открыты для комментариев и предложений.
Будущее с актерами - тема, которая меня очень интересует.
Похожие вопросы
Связанные вопросы
Новые вопросы
scala
Scala - это язык программирования общего назначения, в основном предназначенный для виртуальной машины Java. Разработанный для краткого, элегантного и безопасного для типов представления общих шаблонов программирования, он сочетает в себе как императивный, так и функциональный стили программирования. Его ключевые особенности: продвинутая система статического типа с выводом типа; типы функций; сопоставления с образцом ; неявные параметры и преобразования; перегрузка оператора; полная совместимость с Java; совпадение
Actor
свое внутреннее состояние?Actor
изменит свое внутреннее состояние, то если мы запускаем его в разных потоках, то эта логика может быть неверной (если она зависит от этого состояния). Но если задачаActor
чиста с точки зрения выполняемых функций, я бы также сказал, что она безопасна.Await.result
и закрепленный диспетчер, если мы хотим убедиться, что счетчик обновляется до того, как следующее сообщение будет обработаноreceive
? предположим, что перед блокомFuture {}
мы получаем состояние счетчика. Если мы используем приоритетный почтовый ящик с шаблономresult pipeTo self
, кажется, что счетчик будет непротиворечивым только в конечном итоге?