Uváznutí v Aktor systému

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Uváznutí v Aktor systému
« Odpověď #60 kdy: 23. 10. 2019, 13:51:39 »
Představoval jsem si, že by bylo vhodnější, když by toto řešil systémově runtime, a nikoliv když by si to každý aktor dělal po svém. Ale promyslím si tvé výhrady.
Proč myslíš, že je to vhodnější, a co očekáváš, že tím získáš? Actor sám má nejlepší informace o tom, v jaké fázi komunikace je, a taky vytváří ty data. Pokud použiješ tu session, tak oboje budeš muset předat někam jinam a při každém requestu si to zase brát zpátky. Není lepší si to prostě nechat u sebe? :)

Očekáváš, že když to budeš mít v runtimu na jednom místě, tak se ti to bude líp persistovat? Nebo?

Co to znamená "nechat u sebe"?

Očekávám, že získám
1. věci se budou dělat jedním způsobem
2. aktor bude bezstavovej, to znamená, že mohu zavolat toho samého aktora vícekrát
3. ano, můžu to líp persistovat, i třeba napříč stroji.

Hlavně mám ideu, že mám imutable aktora, který má závislosti na mutable službách.

Když si to bude ten aktor dělat sám, tak
1. bude muset mít stav - jak to budu řešit? Myšlenky mi stále sklouzávají do nějakého toho stavu, který budu muset někam dát.
2. Asi tedy nebudu moct zavolat aktor vícekrát.
3. Aktor si sám bude vyzobávat zprávy které chce. Bude si to sám nějak prioritizovat. Což se mi moc nechce mu tuto svobodu dopřát. Jaké to má výhody?
4. Aby si aktor uchoval stav, tak si zavolá jinej aktor?


Re:Uváznutí v Aktor systému
« Odpověď #61 kdy: 23. 10. 2019, 14:57:02 »
Co to znamená "nechat u sebe"?
Až budu mít chvilku času, pošlu ti ukázkovej kód v Elixiru. Jeden kód vydá za tisíc slov ;)

aktor bude bezstavovej [...] persistovat, i třeba napříč stroji.
Tímhle si vůbec nejsem jist. De facto (z hlediska implementace) totiž ten aktor bude stavovej. Akorát ten stav bude někde jinde. A to mi právě nepřijde elegantní. V Elixiru třeba když máš stavovýho aktora, tak když umře (z libovolnýho důvodu), tak s ním umře i celá jeho paměť - a tím i stav. Automaticky. Nemusíš to nijak řešit. Spíš naopak - pokud bys chtěl stav zachovat i po pádu, musíš to nějak pořešit, ale to obvykle právě nechceš).

Pokud ty budeš držet stav někde mimo toho aktora, jak zjistíš, že ten aktor umřel a stav máš zahodit? Budeš pořád dokola checkovat živost všech stavových aktorů? A dokonce i na vzdálených počítačích ("třeba napříč stroji")?

to znamená, že mohu zavolat toho samého aktora vícekrát
To můžeš i když si stav drží sám. Ukážu ti to na tom kódu později.

Re:Uváznutí v Aktor systému
« Odpověď #62 kdy: 23. 10. 2019, 19:04:46 »
Tak pro tebe mám ty příklady :)

Úplně nejjednodušší actor, jenom abys viděl, jak se v Elixiru spawnují procesy a posílají zprávy:
Kód: [Vybrat]
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/01-simplest.exs

$ elixir 01-simplest.exs
[main] My PID: #PID<0.92.0>
[main] Agent a1 runs with #PID<0.97.0>
[SimplestActor] Got message from #PID<0.92.0>: 1
[SimplestActor] Got message from #PID<0.92.0>: 2

Bezestavový actor poskytující službu "přičti jedničku":
Kód: [Vybrat]
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/02-stateless.exs

$ elixir 02-stateless.exs
[main] My PID: #PID<0.92.0>
[main] Agent a1 runs with #PID<0.97.0>
[StatelessActor] Got message from #PID<0.92.0>: 1
[main] Got reply from actor a1: 2
[StatelessActor] Got message from #PID<0.92.0>: 2
[main] Got reply from actor a1: 3

No a do třetice různý variace na stavovýho actora...

Tohle je úplně chybná implementace, která nepočítá s více klienty a proto zhavaruje:
Kód: [Vybrat]
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/03a-statefull.exs

$ elixir 03a-statefull.exs
[main] My PID: #PID<0.92.0>
[main] Agent a1 runs with #PID<0.97.0>
[ChitChatActor2] Got message from #PID<0.92.0>: :hello
[main] Got reply from actor a1: :hello
[ChitChatActor2] Got message from #PID<0.92.0>: :bye
[ChitChatActor2] Session closed
[ChitChatActor2] Got message from #PID<0.92.0>: :hello
[main] Got reply from actor a1: :hello
[ccc #PID<0.98.0>] Starting
[ccc #PID<0.99.0>] Starting

18:48:20.866 [error] Process #PID<0.98.0> raised an exception
** (RuntimeError) Timeout!
    03a-statefull.exs:90: anonymous fn/1 in :elixir_compiler_0.__FILE__/1

18:48:20.870 [error] Process #PID<0.99.0> raised an exception
** (RuntimeError) Timeout!
    03a-statefull.exs:90: anonymous fn/1 in :elixir_compiler_0.__FILE__/1

Tahle je o trošičku lepší - vybírá zprávy selektivně, takže protokol zpracuje správně, ale pořád je chybná, protože neumí rozlišit sessions (nezajímá ji, od koho která zpráva je, takže klienti by klidně mohli posílat zprávy na střídačku a server by si toho nevšiml):
Kód: [Vybrat]
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/03b-statefull.exs

$ elixir 03b-statefull.exs
[main] Agent a1 runs with #PID<0.97.0>
[ccc #PID<0.98.0>] Starting
[ccc #PID<0.99.0>] Starting
[ChitChatActor2] Got message from #PID<0.98.0>: :hello
[ChitChatActor2] Got message from #PID<0.98.0>: :bye
[ChitChatActor2] Session closed
[ChitChatActor2] Got message from #PID<0.99.0>: :hello
[ccc #PID<0.98.0>] Everything OK
[ChitChatActor2] Got message from #PID<0.99.0>: :bye
[ChitChatActor2] Session closed
[ccc #PID<0.99.0>] Everything OK

No a tohle je už docela slušá implementace, na které můžeš vidět právě to, že si actor drží informace o sessions "u sebe" - a není to nijak zvlášť komplikovaný:
Kód: [Vybrat]
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/f00a01adaafb1623923c9e3469040b9976ce2906/03c-statefull.exs

$ elixir 03c-statefull.exs
[main] Agent a1 runs with #PID<0.97.0>
[ccc #PID<0.98.0>] Starting
[ccc #PID<0.99.0>] Starting
[ChitChatActor3] Got message from #PID<0.98.0>: :hello
[ChitChatActor3] New session #PID<0.98.0>
[ChitChatActor3] Got message from #PID<0.99.0>: :hello
[ChitChatActor3] New session #PID<0.99.0>
[ChitChatActor3] Got message from #PID<0.98.0>: :bye
[ChitChatActor3] session #PID<0.98.0> closed
[ChitChatActor3] Got message from #PID<0.99.0>: :bye
[ChitChatActor3] session #PID<0.99.0> closed
[ccc #PID<0.98.0>] Everything OK
[ccc #PID<0.99.0>] Everything OK

No a tohle už je taková vcelku standardní implementace, která odbavuje každýho klienta pomocí vlastního procesu. Ve skutečné praxi by se to sice psalo trošku jinak, ale všechny základní principy tam jsou implementované dobře (pokud jsem se někde neupsal ;) ):
Kód: [Vybrat]
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/03d-statefull.exs

$ elixir 03d-statefull.exs
[main] Agent a1 runs with #PID<0.99.0>
[ccc #PID<0.100.0>] Starting
[ccc #PID<0.101.0>] Starting
[Proxy] Got message from #PID<0.100.0>: :hello
[Proxy] Creating handler Elixir.ChitChatHandler for session #PID<0.100.0>
[CCH #PID<0.100.0>] Starting
[CCH #PID<0.100.0>] got :hello from #PID<0.100.0>
[Proxy] handlers = %{#PID<0.100.0> => #PID<0.102.0>}
[Proxy] Got message from #PID<0.101.0>: :hello
[Proxy] Creating handler Elixir.ChitChatHandler for session #PID<0.101.0>
[Proxy] handlers = %{#PID<0.100.0> => #PID<0.102.0>, #PID<0.101.0> => #PID<0.103.0>}
[CCH #PID<0.101.0>] Starting
[CCH #PID<0.101.0>] got :hello from #PID<0.101.0>
[Proxy] Got message from #PID<0.100.0>: :bye
[CCH #PID<0.100.0>] got :bye from #PID<0.100.0>
[Proxy] Deleting handler for session #PID<0.100.0>
[Proxy] handlers = %{#PID<0.101.0> => #PID<0.103.0>}
[Proxy] Got message from #PID<0.101.0>: :bye
[CCH #PID<0.101.0>] got :bye from #PID<0.101.0>
[Proxy] Deleting handler for session #PID<0.101.0>
[Proxy] handlers = %{}
[ccc #PID<0.100.0>] Everything OK
[ccc #PID<0.101.0>] Everything OK
« Poslední změna: 23. 10. 2019, 19:09:18 od Mirek Prýmek »

Re:Uváznutí v Aktor systému
« Odpověď #63 kdy: 06. 11. 2019, 19:57:38 »
BoneFlute, co je s tebou? Snad jsi se na to nevykaslal? To by byla skoda!

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Uváznutí v Aktor systému
« Odpověď #64 kdy: 07. 11. 2019, 00:27:48 »
Nevykašlal. Jen moc práce.

Mohl by si se prosím trochu rozkecat ohledně jedné věci, která mi není tak úplně jasná?

(Omlouvám se, ten Elixír je na mě zatím příliš velké sousto.)

...
Tohle je úplně chybná implementace, která nepočítá s více klienty a proto zhavaruje:
...
Tahle je o trošičku lepší - vybírá zprávy selektivně, takže protokol zpracuje správně, ale pořád je chybná, protože neumí rozlišit sessions (nezajímá ji, od koho která zpráva je, takže klienti by klidně mohli posílat zprávy na střídačku a server by si toho nevšiml):
...

Mě tak nějak furt nedochází, proč bych měl těm aktorům dávat volnost, když je pak tak snadné to evidentně napsat špatně. Snad je z mého úvodního příspěvku jasné, že mi jde o to, aby to pokud možno nešlo napsat špatně. Proč nevytvořit specializované třídy aktorů, kterým engine dodá co potřebují, a ony se soustředí na svou práci?

Já ti to věřím, že je to špatně. Ale rád bych pochopil proč, nějaký příklad, ukázku, a tak.


Re:Uváznutí v Aktor systému
« Odpověď #65 kdy: 07. 11. 2019, 11:00:28 »
Mě tak nějak furt nedochází, proč bych měl těm aktorům dávat volnost, když je pak tak snadné to evidentně napsat špatně.
Protože jestli je to dobře nebo špatně záleží na tom, co implementuješ. V základu můžeš mít stavového a nestavového aktora a stavový a nestavový protokol. Souvisí to spolu, ale ne těsně, takže to je ortogonální => z tohodle pohledu můžeš mít celkem 4 možnosti toho, co chceš implementovat. A co je korektní v jedné nemusí být korektní v druhé.

Jinak ale ta tvoje myšlenka je správná, akorát se to řeší jinak: nějaká základní "šablona" aktoru je ve standardní knihovně a ty dodáš jenom callbacky implementující tu tvoji kýženou funkcionalitu. V erlang světě je taková nejčastější "šablona" http://erlang.org/doc/man/gen_server.html (implementuje stavováho aktora implementujícího potenciálně stavový protokol).

Takže máš vlastně pravdu, akorát se to nedělá na úrovni jazyka, kde by to bylo těžký a matoucí, ale na úrovni knihovny.