Akka este o bibliotecă pentru limbile Java și Scala, care implementează agenți, actori, interacțiune între actori în rețea și multe alte facilități. În prima aproximare se pare că Erlang sau Cloud Haskell. dar, de fapt, Akka este mult mai puternic. De exemplu, utilizând Akka, puteți combina cu ușurință mai multe mașini într-un grup, în care dispariția și aspectul mașinilor vor fi monitorizate, iar actorii se vor muta automat de la mașină la mașină pe măsura modificării dimensiunii clusterului. Și acesta este doar un exemplu. În această notă, vom scrie o aplicație foarte simplă care folosește Akka pentru a arăta cât de ușor este să lucrați cu această bibliotecă.
Se presupune, de asemenea, că știi ce este un model de actori și că știi cum să lucrezi cu Futura în Scala.
Deschideți build.sbt și conectați Akka la proiectul nostru:
bibliotecăDependințele + =
"com.typesafe.akka" %% "akka-actor"% "2.3.6"
Să scriem cel mai simplu actor care stochează perechi cheie-valoare:
clasa case SetRequest # 40; cheie. String, valoare. șir # 41;
caz de clasă GetRequest # 40; cheie. șir # 41;
caz de clasă GetResponse # 40; cheie. opțiune # 91; șir # 93; # 41;
clasa MapActor extinde Actor cu ActorLogging # 123;
val de stat. mutabil. hartă # 91; String, String # 93; = mutable. Harta. gol
def primi = # 123;
cazul r. SetRequest =>
stare + = r. cheie -> r. valoare
cazul r. GetRequest =>
expeditor. GetResponse # 40; de stat. obține # 40; r. cheie # 41; # 41;
cazul r =>
log. avertisment # 40; s "Neașteptat: $ r" # 41;
# 125;
# 125;
După cum puteți vedea, totul este destul de simplu. Primind un mesaj de tipul SetRequest, actorul salvează o pereche cheie-valoare în cheie. Dacă actorul primește GetRequest, el găsește valoarea tastei pass în Map și trimite cererea către expeditorul cererii GetResponse cu valoarea opțiunii type # 91; șir # 93; .
Pentru a începe actorii, trebuie să creăm un ActorSystem:
obiect Exemplul 2 extinde aplicația # 123;
sistem val = ActorSystem # 40; „Sistemul“ # 41;
val mainActor = sistem. actorOf # 40; recuzită # 40; noul MainActor # 41;. "MainActor" # 41;
sistem. awaitTermination # 40; # 41;
# 125;
Aici vom crea un singur actor MainActor și vom aștepta finalizarea sistemului ActorSystem. MainActor este definit după cum urmează:
cazul obiect Start
clasa MainActor extinde Actor cu ActorLogging # 123;
implicit val timeout = Timeout # 40; 5 secunde # 41;
val mapActor = context. actorOf # 40; recuzită # 40; noul MapActor # 41;. "MapActor" # 41;
override def preStart # 40; # 41; # 123;
de sine. start
# 125;
def primi = # 123;
caz Start =>
mapActor. "solicitare falsă"
mapActor. SetRequest # 40; „Cheia“. „Valoarea“ # 41;
val respF = mapActor. GetRequest # 40; „Cheia“ # 41;
Fereastra resp
cazul r. GetResponse =>
log. avertisment # 40; s "Răspuns: $ r" # 41;
context. sistem. închidere # 40; # 41;
# 125;
# 125;
După cum puteți vedea, MapActor este creat aici, pe care l-am definit mai devreme. De asemenea, la pornire, MainActor trimite un mesaj de start (a se vedea metoda preStart). La primirea acestui mesaj, actorul trimite trei mesaje la MapActor. Trimiterea primelor două mesaje apare pe principiul focului și uită. Dar când trimiteți o cerere la GetRequest, actorul se așteaptă să primească un fel de răspuns, deci în schimb. (pronunțat "spune" sau "bang") este utilizat de operator. (pronunțată "cere").
Acesta din urmă returnează un futura cu răspunsul serverului respF. Astfel, nu există blocare, spre deosebire, de exemplu, de la gen_server: apel la Erlang. Apoi, folosind pipeTo combinator, vom transmite răspuns atunci când devine disponibil pentru noi înșine. Inutil să spun, pipeTo funcționează nu numai cu sine, ci și cu alți actori. Când MainActor primește în cele din urmă un răspuns (GetResponse), îl trimite simplu în jurnal și apoi oprește ActorSystem.
Apropo, este pentru operator. este nevoie de un argument temporal implicit.
Codul programului:
împachetați-mă. EAX. akka_examples
import akka. actor. _
import akka. model. # 123; întrebați, țeava # 125;
import akka. UTIL. timeout
scala de import. de colectare. _
scala de import. concurente. durată. _
scala de import. concurente. ExecutionContext. Implicits. la nivel mondial
clasa case SetRequest # 40; cheie. String, valoare. șir # 41;
caz de clasă GetRequest # 40; cheie. șir # 41;
caz de clasă GetResponse # 40; cheie. opțiune # 91; șir # 93; # 41;
clasa MapActor extinde Actor cu ActorLogging # 123;
val de stat. mutabil. hartă # 91; String, String # 93; = mutable. Harta. gol
def primi = # 123;
cazul r. SetRequest =>
stare + = r. cheie -> r. valoare
cazul r. GetRequest =>
expeditor. GetResponse # 40; de stat. obține # 40; r. cheie # 41; # 41;
cazul r =>
log. avertisment # 40; s "Neașteptat: $ r" # 41;
# 125;
# 125;
cazul obiect Start
clasa MainActor extinde Actor cu ActorLogging # 123;
implicit val timeout = Timeout # 40; 5 secunde # 41;
val mapActor = context. actorOf # 40; recuzită # 40; noul MapActor # 41;. "MapActor" # 41;
override def preStart # 40; # 41; # 123;
de sine. start
# 125;
def primi = # 123;
caz Start =>
mapActor. "solicitare falsă"
mapActor. SetRequest # 40; „Cheia“. „Valoarea“ # 41;
val respF = mapActor. GetRequest # 40; „Cheia“ # 41;
Fereastra resp
cazul r. GetResponse =>
log. avertisment # 40; s "Răspuns: $ r" # 41;
context. sistem. închidere # 40; # 41;
# 125;
# 125;
obiect Exemplul 2 extinde aplicația # 123;
sistem val = ActorSystem # 40; „Sistemul“ # 41;
val mainActor = sistem. actorOf # 40; recuzită # 40; noul MainActor # 41;. "MainActor" # 41;
sistem. awaitTermination # 40; # 41;
# 125;
Ieșirea programului (timbrele și informațiile despre expeditor sunt omise):
[akka: // system / user / mainActor / mapActor] Neașteptat: solicitare falsă
[akka: // system / user / mainActor] Răspuns: GetResponse (Unele (valoare))
Dar unul dintre cititori lucrează ocazional cu Akka?