Uvod u Akka glumce na Javi

1. Uvod

Akka je biblioteka otvorenog koda koja pomaže u lakom razvoju istodobnih i distribuiranih aplikacija koristeći Javu ili Scalu iskorištavanjem glumačkog modela.

U ovom vodiču, predstavit ćemo osnovne značajke poput definiranja glumaca, kako komuniciraju i kako ih možemo ubiti. U završnim napomenama također ćemo primijetiti neke najbolje prakse tijekom rada s Akkom.

2. Glumački model

Model glumca nije nov za zajednicu računalnih znanosti. Prvi ga je predstavio Carl Eddie Hewitt 1973. godine, kao teorijski model za rukovanje istodobnim računanjem.

Svoju praktičnu primjenjivost počeo je pokazivati ​​kad je softverska industrija počela shvaćati zamke uvođenja istodobnih i distribuiranih aplikacija.

Glumac predstavlja neovisnu računarsku jedinicu. Neke važne karakteristike su:

  • glumac enkapsulira njegovo stanje i dio logike aplikacije
  • glumci komuniciraju samo putem asinkronih poruka, a nikada putem izravnih poziva metode
  • svaki glumac ima jedinstvenu adresu i poštanski sandučić u koji drugi glumci mogu dostavljati poruke
  • glumac će obraditi sve poruke u poštanskom sandučiću u slijedu (zadana implementacija poštanskog sandučića je FIFO red)
  • sustav glumaca organiziran je u hijerarhiji nalik stablu
  • glumac može stvoriti druge glumce, može slati poruke bilo kojem drugom glumcu i zaustaviti se ili je bilo koji glumac stvoren

2.1. Prednosti

Razvoj istodobne aplikacije težak je jer se moramo nositi sa sinkronizacijom, zaključavanjima i dijeljenom memorijom. Korištenjem Akka glumaca lako možemo napisati asinkroni kod bez potrebe za zaključavanjem i sinkronizacijom.

Jedna od prednosti upotrebe poruka umjesto poziva metoda je ta nit pošiljatelja neće blokirati čekanje povratne vrijednosti kad pošalje poruku drugom glumcu. Akter primatelj odgovorit će s rezultatom slanjem poruke odgovora pošiljatelju.

Još jedna velika prednost korištenja poruka je ta što se ne moramo brinuti o sinkronizaciji u okruženju s više niti. To je zbog činjenice da sve se poruke obrađuju uzastopno.

Još jedna prednost Akka modela glumca je rukovanje pogreškama. Organizirajući glumce u hijerarhiji, svaki glumac može obavijestiti svog roditelja o neuspjehu, pa se može ponašati u skladu s tim. Roditelj glumac može odlučiti zaustaviti ili ponovno pokrenuti dijete glumce.

3. Postavljanje

Da bismo iskoristili prednosti Akka glumaca, moramo dodati sljedeću ovisnost iz Maven Central:

 com.typesafe.akka akka-glumac_2.12 2.5.11 

4. Stvaranje glumca

Kao što je spomenuto, akteri su definirani u hijerarhijskom sustavu. Svi akteri koji dijele zajedničku konfiguraciju definirat će se ActorSystem.

Za sada ćemo jednostavno definirati ActorSystem sa zadanom konfiguracijom i prilagođenim imenom:

ActorSystem sustav = ActorSystem.create ("test-sustav"); 

Iako još nismo stvorili nijednog glumca, sustav će već sadržavati 3 glavna glumca:

  • root skrbnik glumac koji ima adresu “/” koja, kako naziv kaže, predstavlja korijen hijerarhije sustava glumca
  • glumac skrbnik korisnika koji ima adresu “/ korisnik”. Ovo će biti roditelj svih glumaca koje definiramo
  • glumac skrbnik sustava koji ima adresu “/ system”. To će biti roditelj za sve aktere koje interno definira sustav Akka

Bilo koji Akka glumac produžit će SažetakGlumac apstraktna klasa i implementirati createReceive () metoda za rukovanje dolaznim porukama drugih aktera:

javna klasa MyActor proširuje AbstractActor {public Receive createReceive () {return receiveBuilder (). build (); }}

Ovo je najosnovniji glumac kojeg možemo stvoriti. Može primati poruke od drugih aktera i odbacit će ih jer u. Nisu definirani odgovarajući obrasci poruka ReceiveBuilder. O podudaranju uzoraka poruka razgovarat ćemo kasnije u ovom članku.

Sad kad smo stvorili svog prvog glumca, trebali bismo ga uključiti u ActorSystem:

ActorRef readingActorRef = system.actorOf (Props.create (MyActor.class), "moj-glumac");

4.1. Konfiguracija glumca

The Rekviziti klasa sadrži konfiguraciju glumca. Možemo konfigurirati stvari poput dispečera, poštanskog sandučića ili konfiguracije implementacije. Ova je klasa nepromjenjiva, stoga je sigurna u nitima, pa se može dijeliti prilikom stvaranja novih glumaca.

Preporučuje se i smatra najboljom praksom definiranje tvorničkih metoda unutar objekta glumca koji će se baviti stvaranjem Rekviziti objekt.

Kao primjer, definirajmo glumca koji će izvršiti određenu obradu teksta. Glumac će dobiti a Niz objekt na kojem će obaviti obradu:

javna klasa ReadingActor proširuje AbstractActor {private String text; javni statički rekviziti rekvizita (tekst niza) {return Props.create (ReadingActor.class, text); } // ...}

Sada, da bismo stvorili primjerak ove vrste glumca, samo koristimo rekviziti() tvornička metoda za prosljeđivanje Niz argument konstruktoru:

ActorRef readingActorRef = system.actorOf (ReadingActor.props (TEXT), "readingActor");

Sad kad znamo definirati glumca, pogledajmo kako oni komuniciraju unutar glumačkog sustava.

5. Poruke glumca

Da bi međusobno komunicirali, glumci mogu slati i primati poruke od bilo kojeg drugog aktera u sustavu. Ovi poruke mogu biti bilo koja vrsta objekta uz uvjet da je nepromjenjiva.

Najbolja je praksa definirati poruke unutar klase glumca. To pomaže u pisanju koda koji je lako razumljiv i koji zna koje poruke glumac može obraditi.

5.1. Slanje poruka

Unutar sustava Akka glumca poruke se šalju metodama:

  • reći()
  • pitaj ()
  • naprijed()

Kad želimo poslati poruku i ne očekujemo odgovor, možemo koristiti reći() metoda. Ovo je najučinkovitija metoda iz perspektive izvedbe:

readingActorRef.tell (novi ReadingActor.ReadLines (), ActorRef.noSender ()); 

Prvi parametar predstavlja poruku koju šaljemo na adresu glumca readingActorRef.

Drugi parametar određuje tko je pošiljatelj. To je korisno kada glumac koji prima poruku mora poslati odgovor glumcu koji nije pošiljatelj (na primjer roditelju glumca koji šalje).

Obično drugi parametar možemo postaviti na null ili ActorRef.noSender (), jer ne očekujemo odgovor. Kad trebamo odgovor glumca, možemo koristiti pitaj () metoda:

CompletableFuture future = ask (wordCounterActorRef, novi WordCounterActor.CountWords (redak), 1000) .toCompletableFuture ();

Kada traži odgovor od glumca a CompletionStage objekt se vraća, tako da obrada ostaje neblokirajuća.

Vrlo važna činjenica na koju moramo obratiti pažnju jest postupanje s pogreškama iznutra, glumca koji će odgovoriti. Za povratak a Budućnost objekt koji će sadržavati iznimku moramo poslati a Status.Neuspjeh poruka glumcu pošiljatelju.

To se ne radi automatski kada glumac tijekom obrade poruke i datoteke izbaci iznimku pitaj () poziv će isteći, a u zapisnicima se neće vidjeti referenca na iznimku:

@Override public Receive createReceive () {return receiveBuilder () .match (CountWords.class, r -> {try {int numberOfWords = countWordsFromLine (r.line); getSender (). Tell (numberOfWords, getSelf ());} catch (Iznimka ex) {getSender (). Tell (new akka.actor.Status.Failure (ex), getSelf ()); throw ex;}}). Build (); }

Također imamo naprijed() metoda koja je slična reći(). Razlika je u tome što se izvorni pošiljatelj poruke zadržava prilikom slanja poruke, pa glumac koji prosljeđuje poruku djeluje samo kao posrednik:

printerActorRef.forward (novi PrinterActor.PrintFinalResult (totalNumberOfWords), getContext ());

5.2. Primanje poruka

Svaki će glumac implementirati createReceive () metoda, koji obrađuje sve dolazne poruke. The receiveBuilder () ponaša se kao naredba prekidača, pokušavajući podudariti primljenu poruku s definiranom vrstom poruka:

javni Receive createReceive () {return receiveBuilder (). matchEquals ("printit", p -> {System.out.println ("Adresa ovog glumca je:" + getSelf ());}). build (); }

Kad se primi, poruka se stavi u FIFO red, tako da se s porukama postupa uzastopno.

6. Ubojstvo glumca

Kad smo završili s glumcem možemo to zaustaviti pozivom na Stop() metoda od ActorRefFactory sučelje:

system.stop (myActorRef);

Ovom metodom možemo prekinuti bilo koje dijete glumac ili samog glumca. Važno je napomenuti da se zaustavljanje vrši asinkrono i da se trenutna obrada poruka će završiti prije nego što glumac bude prekinut. Više neće biti prihvaćene dolazne poruke u poštanski sandučić glumca.

Po zaustavljanje roditelja glumca, također ćemo poslati signal za ubojstvo svoj djeci glumcima koje je to iznjedrilo.

Kad sustav glumca više ne trebamo, možemo ga prekinuti kako bismo oslobodili sve resurse i spriječili curenje memorije:

Budući terminateResponse = system.terminate ();

Ovo će zaustaviti glumce čuvara sustava, dakle sve aktere definirane u ovom Akka sustavu.

Mogli bismo poslati i PoisonPill poruka bilo kojem glumcu kojeg želimo ubiti:

myActorRef.tell (PoisonPill.getInstance (), ActorRef.noSender ());

The PoisonPill glumac će primiti poruku kao i svaku drugu poruku i staviti je u red čekanja. Glumac će obrađivati ​​sve poruke dok ne dođe do PoisonPill jedan. Tek tada će glumac započeti postupak raskida.

Druga posebna poruka koja se koristi za ubojstvo glumca je Ubiti poruka. Za razliku od PoisonPill, glumac će baciti ActorKilledException prilikom obrade ove poruke:

myActorRef.tell (Kill.getInstance (), ActorRef.noSender ());

7. Zaključak

U ovom smo članku predstavili osnove Akka okvira. Pokazali smo kako definirati glumce, kako međusobno komuniciraju i kako ih prekinuti.

Zaključit ćemo s nekoliko najboljih praksi tijekom rada s Akkom:

  • koristiti reći() umjesto pitaj () kada je izvedba zabrinjavajuća
  • prilikom korištenja pitaj () uvijek bismo se trebali nositi s iznimkama slanjem a Neuspjeh poruka
  • glumci ne bi trebali dijeliti bilo kakvo promjenjivo stanje
  • glumac ne bi trebao biti deklariran unutar drugog glumca
  • glumci se ne zaustavljaju automatski kad se na njih više ne upućuje. Moramo izričito uništiti glumca kad nam više ne treba kako bismo spriječili curenje memorije
  • poruke koje koriste glumci uvijek treba biti nepromjenjiv

Kao i uvijek, izvorni kôd članka dostupan je na GitHubu.