Статьи

стать / не стать — Открывая Акку

Иногда нашему актеру нужно реагировать по-разному в зависимости от его внутреннего состояния. Обычно получение какого-то определенного сообщения вызывает изменение состояния, которое, в свою очередь, меняет способ обработки последующих сообщений. Другое сообщение восстанавливает исходное состояние и, следовательно, способ, которым сообщения обрабатывались ранее. В предыдущей статье мы реализовали актер waitingForResponse на waitingForResponse флага waitingForResponse . Это излишне сложная и без того сложная логика обработки сообщений:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var waitingForResponse = false
 
def receive = {
case RandomRequest =>
preFetchIfAlmostEmpty()
if(buffer.isEmpty) {
backlog += sender
} else {
sender ! buffer.dequeue()
}
case RandomOrgServerResponse(randomNumbers) =>
buffer ++= randomNumbers
waitingForResponse = false
while(!backlog.isEmpty && !buffer.isEmpty) {
backlog.dequeue() ! buffer.dequeue()
}
preFetchIfAlmostEmpty()
}
 
private def preFetchIfAlmostEmpty() {
if(buffer.size <= BatchSize / 4 && !waitingForResponse) {
randomOrgClient ! FetchFromRandomOrg(BatchSize)
waitingForResponse = true
}
}

Не проще ли иметь два разных метода receive один используется, когда мы ожидаем ответа от внешнего сервера ( waitingForResponse == true ), а другой — когда буфер заполнен достаточно, а запрос к random.org еще не random.org ? В таких условиях методы become() и unbecome() очень полезны. По умолчанию метод receive используется для обработки всех входящих сообщений. Однако, в любое время мы можем вызвать стал (), который принимает любой метод, соответствующий подписи получения, в качестве аргумента. Каждое последующее сообщение будет обрабатываться этим новым методом. Вызов unbecome() восстанавливает оригинальный метод receive . Зная эту технику, мы можем рефакторинг нашего решения выше:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def receive = {
case RandomRequest =>
preFetchIfAlmostEmpty()
handleOrQueueInBacklog()
}
 
def receiveWhenWaiting = {
case RandomRequest =>
handleOrQueueInBacklog()
case RandomOrgServerResponse(randomNumbers) =>
buffer ++= randomNumbers
context.unbecome()
while(!backlog.isEmpty && !buffer.isEmpty) {
backlog.dequeue() ! buffer.dequeue()
}
preFetchIfAlmostEmpty()
}
 
private def handleOrQueueInBacklog() {
if (buffer.isEmpty) {
backlog += sender
} else {
sender ! buffer.dequeue()
}
}
 
private def preFetchIfAlmostEmpty() {
if(buffer.size <= BatchSize / 4) {
randomOrgClient ! FetchFromRandomOrg(BatchSize)
context become receiveWhenWaiting
}
}

Мы извлекли код, отвечающий за обработку сообщения, пока мы random.org ответа random.org в отдельный метод receiveWhenWaiting . Обратите внимание на вызовы become() и unbecome() — они заменили ненужный флаг waitForResponse. Вместо этого мы просто говорим: начиная со следующего сообщения, пожалуйста, используйте этот другой метод для обработки (станьте немного другим актером). Позже мы говорим: хорошо, давайте вернемся к исходному состоянию и получим сообщения, как вы привыкли (не получилось). Но самое важное изменение — это переход от одного большого метода к двум, гораздо меньшим и лучшим именам.
unbecome() become() и unbecome() самом деле намного мощнее, поскольку они внутренне поддерживают стек приемных методов. Каждый вызов функции discardOld = false become()discardOld = false в качестве второго параметра) помещает текущий метод получения в стек, а unbecome() его и восстанавливает предыдущий. Таким образом, мы можем использовать become() чтобы использовать несколько методов получения, а затем постепенно возвращаться ко всем изменениям. Кроме того, Akka также поддерживает шаблон конечного автомата , но об этом, возможно, в будущем.
Исходный код этой статьи доступен на GitHub в become-unbecome tag .

Это был перевод моей статьи « Познаемый Акка: стать / негодным », первоначально опубликованной на scala.net.pl .

Ссылка: станьте / не станьте — узнайте об Akka от нашего партнера по JCG Томаша Нуркевича в блоге о Java и соседстве .