DevStart Blogi Napisano Listopad 9, 2015 Zgłoś Udostępnij Napisano Listopad 9, 2015 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. Wyświetl pełny artykuł Cytuj Link do komentarza Udostępnij na innych stronach More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.