W kolejnych wpisach chciałbym opisać framework akka.net. Zanim jednak przejdę do opisu API, warto poświęcić chwilę (myślę, że około dwa wpisy) na zasadę działania “actor model”.
Aktor jest modelem budowania aplikacji wielowątkowych. Powstał w celu ułatwienia synchronizacji między różnymi wątkami. Programiści piszący aplikacje wielowątkowe zwykle korzystają z klasycznych blokad (lock) w celu opisania sekcji krytycznej. W wielu sytuacjach jest to najlepszy i najprostszy sposób. Niestety dla dużych i skomplikowanych systemów, utrzymywanie takiego kodu jest bardzo trudne, mozolne i niezwykłe podatne na powstanie deadlock lub livelock.
Dzięki odpowiedniemu podziałowi kodu, można uniknąć powyższych problemów na poziomie projektu klas. Wspomniany aktor to nic innego jak klasa, która spełnia pewne wymagania:
– przechowuje stan (zawiera np. pola lub właściwości)
– implementuje logikę (zawiera zatem metody)
– jest reprezentowana przez wątek
– komunikuje się z innymi aktorami za pomocą asynchronicznych wiadomości
– wiadomości nie mogą być modyfikowalne (zatem są “immutable”).
– aktor może przetwarzać wyłącznie jedną wiadomość danym momencie – pozostałe są kolejkowanie
– stan aktora nie może być modyfikowany bezpośrednio przez zewnętrzne obiekty
Myślę, że to najważniejsze właściwości modelu. W świecie C#, aktor będzie zatem klasą wykonywaną na osobnym wątku albo zadaniu (task – TPL). Taka klasa nie będzie eksponowała setter’ów. Wszystkie właściwości mogą być tylko do odczytu. Musimy zagwarantować, że aktor nie jest modyfikowany przez cokolwiek innego. Stan aktora za to może być modyfikowany przez niego samego.
Kluczową rolę pełnią tutaj asynchroniczne wiadomości. Jeśli ktoś jest zaznajomiony z nServiceBus czy nawet opisanym w zeszłym tygodniu Hangfire, powinien rozumieć systemy kolejkowe. W najprostszej postaci, wspomniana klasa (aktor) będzie zawierała kolekcję odebranych wiadomości. Następnie w wątku, będą one zdejmowane i przetwarzane jedna po drugim. Konieczne jest, aby dany aktor, przetwarzał wyłącznie jedną wiadomość w dowolnym czasie. Dzięki temu, nie musimy martwić się o synchronizację. Mamy zagwarantowane zatem:
– jeden aktor to wyłącznie jeden wątek
– stan aktora nie jest modyfikowany na zewnątrz
– żadne blokady nie są wymagane.
To bardzo ułatwia pracę. Nie musimy korzystać z żadnych blokad, ponieważ dany kod jest wykonywany wyłącznie przed jeden wątek. Sekcje krytyczną zastąpiono zatem asynchronicznymi wiadomościami. Jeśli wątek A chce odczytać albo zmienić stan wątku B, wykonuje to przez asynchroniczne wiadomości.
Zwykle systemy tworzą hierarchie aktorów, uformowane w postaci drzew. Każdy aktor może mieć swojego rodzica (zarządcę). Zwykle dany problem rozbija się na taką liczbę aktorów, aby pojedynczy aktor mógł wykonywać kod bez żadnej synchronizacji. Jeśli dany problem składa się z operacji wymagających sekcji krytycznych, wtedy rozdzielamy go jeszcze bardziej, tworząc kolejny poziom w drzewie aktorów.
Najtrudniejszym element w wielowątkowości jest modyfikacja stanu współdzielonego. W przypadku aktorów, takiego stanu po prostu nie ma. Każdy aktor pracuje niezależnie od siebie. Jeśli dane jednego aktora potrzebne są przez drugiego, przesyłane są w formie niemodyfikowalnych, asynchronicznych wiadomości.
Dla prostych problemów, model może okazać się zbyt skomplikowany. Czasami łatwiej jest stworzyć sekcję krytyczną w formie blokady, niż implementować kilka klas komunikujących się za pomocą wiadomości. W przyszłym poście, pokażę realny problem, zaimplementowany najpierw za pomocą blokady lock, a potem w w postaci aktorów.
Po przeczytaniu tego artykułu nadal nie mam pojecia o co kaman
Moze przyklad w nastepnym wpisie cos rozjasni. To nie jest trudne, ale sam opis moze byc zbyt abstrakcyjny (to zupelnie inny model niz ten oparty na blokadach). To troche jak programowanie proceduralne vs obiektowe.
Mysle ze najlepiej zrozumiec sama idee uzywajac przykladow.
Osobiscie polecam
https://github.com/petabridge/akka-bootcamp
Tak naprawdę Actors model to jest coś więcej niż jedynie wzorzec programowania wielowątkowego. Stanowi on fundament do tworzenia aplikacji w ramach FRP (Functional Reactive Programming) . Jego odpowiednik to CSP. W ramach modelu Actors występuję wiele wzorców programowania . Actors model jest tak stary, jak języki programowania w ramach FRP, czyli Haskell i Erlang, a został ponowanie “odkryty” w JVM-Scala. Zaś CSP jest wykorzystywany w ostatnio modnym języku Golang.