Из вводной первой части заметок Akka мы увидели актеров с высоты птичьего полета в Akka Toolkit. Во второй части заметок Akka мы рассмотрим раздел «Актеры». Что касается примера, мы будем использовать тот же пример ученика-учителя, который мы обсуждали ранее.
В этой первой части Actor Messaging мы создадим Teacher Actor, а вместо Student Actor будем использовать основную программу StudentSimulatorApp .
Пересмотр ученика-учителя в деталях
Давайте пока рассмотрим сообщение, отправленное приложением StudentSimulatorApp одному только TeacherActor. Когда я говорю « StudentSimulatorApp , я имею в виду обычную основную программу.
Картина передает это:
(если условия ошеломляющие, не волнуйтесь, мы рассмотрим их подробно)
- Студент создает то, что называется
ActorSystem - Он использует ActorSystem для создания чего-то, называемого
ActorRef. СообщениеQuoteRequestотправляется ActorRef (прокси для TeacherActor) - Актер ref передает сообщение
Dispatcher - Диспетчер помещает сообщение в почтовый ящик целевого
MailBox. - Затем диспетчер помещает
Mailboxв поток (подробнее об этом в следующем разделе). - Почтовый ящик удаляет сообщение и в конечном итоге делегирует его фактическому методу получения Актера Учителя.
Как я уже сказал, не беспокойся об этом. Давайте рассмотрим каждый шаг подробнее. Вы можете вернуться и вернуться к этим пяти шагам, как только мы закончим.
Программа StudentSimulatorApp
Мы будем использовать это StudentSimulatorApp для вызова JVM и инициализации ActorSystem.
Как мы понимаем из картинки, StudentSimulatorApp
- Создает ActorSystem
- Использует ActorSystem для создания прокси для Учителя Actor (ActorRef)
- Отправляет сообщение QuoteRequest на прокси.
Давайте сосредоточимся только на этих трех моментах.
-
Создание ActorSystem
-
Создание прокси для TeacherActor?
-
Отправить
QuoteRequestв прокси
ActorSystem является точкой входа в ActorWorld. ActorSystems — это система, с помощью которой вы можете создавать и останавливать Актеров. Или даже отключить всю среду актера.
На другом конце спектра субъекты являются иерархическими, и система ActorSystem также похожа на java.lang.Object или scala.Any для всех scala.Any — это означает, что она является корнем для всех субъектов. Когда вы создаете Actor с помощью метода actorOf actorOf , вы создаете Actor чуть ниже ActorSystem.
Код для инициализации ActorSystem выглядит так:
|
1
|
val system=ActorSystem("UniversityMessageSystem") |
UniversityMessageSystem — это просто симпатичное имя, которое вы даете своей ActorSystem.
Давайте рассмотрим следующий фрагмент:
|
1
|
val teacherActorRef:ActorRef=actorSystem.actorOf(Props[TeacherActor]) |
actorOf — это метод создания Actor в ActorSystem. Но, как видите, он не возвращает TeacherActor, который нам нужен. Возвращает что-то типа ActorRef .
ActorRef действует как прокси для настоящих актеров. Клиенты не общаются напрямую с актером. Это способ Actor Model, позволяющий избежать прямого доступа к любым пользовательским / частным методам или переменным в TeacherActor или любом Actor ради этого.
Повторим, вы отправляете сообщения только ActorRef, и он в конечном итоге достигает вашего действующего актера. Вы никогда не можете говорить с вашим актером напрямую. Люди будут ненавидеть тебя до смерти, если ты найдешь несколько подлых способов сделать это.
Это снова один лайнер. Вы просто tell сообщение QuoteRequest ActorRef. Метод Tell в Actor действительно есть ! , (в ActorRef также есть метод Tell, который просто делегирует обратный вызов ! )
|
1
2
|
//send a message to the Teacher Actor teacherActorRef!QuoteRequest |
Это оно !!!
Если вы думаете, что я лгу, проверьте весь код приложения StudentSimulatorApp ниже:
StudentSimulatorApp.scala
|
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
|
package me.rerun.akkanotes.messaging.firenforgetimport akka.actor.ActorSystem import akka.actor.Props import akka.actor.actorRef2Scala import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._object StudentSimulatorApp extends App{ //Initialize the ActorSystem val actorSystem=ActorSystem("UniversityMessageSystem") //construct the Teacher Actor Ref val teacherActorRef=actorSystem.actorOf(Props[TeacherActor]) //send a message to the Teacher Actor teacherActorRef!QuoteRequest //Let's wait for a couple of seconds before we shut down the system Thread.sleep (2000) //Shut down the ActorSystem. actorSystem.shutdown()} |
Ну, я немного обманул. Вам придется shutdown ActorSystem или иным образом, JVM продолжает работать вечно. И я заставляю основной поток спать некоторое время, просто чтобы TeacherActor завершил свою задачу. Я знаю, это звучит глупо. Не беспокойся об этом. Мы напишем несколько аккуратных тестовых примеров в следующей части, чтобы избежать этого взлома.
Сообщение
Мы только что сказали QuoteRequest ActorRef, но мы вообще не видели класс сообщения !!
Вот оно:
(Рекомендуется переносить ваши сообщения в хороший объект для упрощения организации)
TeacherProtocol
|
1
2
3
4
5
6
7
8
|
package me.rerun.akkanotes.messaging.protocolsobject TeacherProtocol{ case class QuoteRequest() case class QuoteResponse(quoteString:String)} |
Как вы знаете, QuoteRequest предназначен для запросов, поступающих в TeacherActor. Актер ответил бы в ответ с QuoteResponse .
Диспетчер и почтовый ящик
ActorRef делегирует функциональность обработки сообщений Dispatcher . Под капотом, пока мы создавали ActorSystem и ActorRef , был создан Dispatcher и MailBox . Посмотрим, о чем они.
MailBox
Каждый актер имеет один почтовый ящик (мы рассмотрим один особый случай позже). По нашей аналогии, у каждого Учителя тоже есть один почтовый ящик. Учитель должен проверить почтовый ящик и обработать сообщение. В мире Actor все наоборот — почтовый ящик, когда появляется возможность, использует Actor для выполнения своей работы.
Также у почтового ящика есть очередь для хранения и обработки сообщений в формате FIFO — немного отличающаяся от нашей обычной папки входящих сообщений, где самая последняя — та, что вверху.
Теперь диспетчер
Диспетчер делает действительно классные вещи. Судя по всему, Dispatcher просто получает сообщение от ActorRef и передает его в почтовый ящик. Но за кулисами происходит одна удивительная вещь:
Диспетчер упаковывает ExecutorService (ForkJoinPool или ThreadPoolExecutor). Он выполняет MailBox этого ExecutorService.
Проверьте этот фрагмент из Диспетчера :
|
1
2
3
4
5
6
|
protected[akka] override def registerForExecution(mbox: Mailbox, ...): Boolean = { ... try { executorService execute mbox ...} |
Какая? Вы только что сказали, что выполняете почтовый ящик?
Ага. Мы уже видели, что почтовый ящик содержит все сообщения в очереди. Также, поскольку Исполнитель запускает MailBox , Почтовый ящик должен быть Thread . Вы правы. Это в значительной степени объявление и конструктор MailBox.
Вот подпись почтового ящика :
|
1
|
private[akka] abstract class Mailbox(val messageQueue: MessageQueue) extends SystemMessageQueue with Runnable |
Учитель актер
Почтовый ящик, когда у него run метод run , извлекает сообщение из очереди сообщений и передает его Actor для обработки.
Метод, который в конечном итоге ActorRef когда вы tell сообщение ActorRef является методом receive целевого Actor.
TeacherActor — это элементарный класс, который имеет List цитат и, очевидно, метод receive который обрабатывает сообщения.
Проверь это :
TeacherActor.scala
|
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
33
34
35
36
37
38
39
40
|
package me.rerun.akkanotes.messaging.firenforgetimport scala.util.Randomimport akka.actor.Actor import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._/* * Your Teacher Actor class. * * The class could use refinement by way of * using ActorLogging which uses the EventBus of the Actor framework * instead of the plain old System out * */class TeacherActor extends Actor { val quotes = List( "Moderation is for cowards", "Anything worth doing is worth overdoing", "The trouble is you think you have time", "You never gonna know if you never even try") def receive = { case QuoteRequest => { import util.Random //Get a random Quote from the list and construct a response val quoteResponse=QuoteResponse(quotes(Random.nextInt(quotes.size))) println (quoteResponse) } }} |
Шаблон метода приема QuoteRequest соответствует только одному сообщению — QuoteRequest (на самом деле, это хорошая практика для сопоставления с шаблоном по умолчанию, но есть интересная история, которую нужно там рассказать)
Все, что делает метод приема, это
- образец соответствия для
QuoteRequest - выбрать случайную цитату из статического списка цитат
- построить
QuoteResponse - напечатайте QuoteResponse на консоль
Код
- Весь проект можно скачать с github здесь .
Мы расскажем о более интересных вещах в следующих частях …
| Ссылка: | Akka Notes — Actor Messaging — 1 от нашего партнера JCG Аруна Маниваннана в блоге Rerun.me . |





