Połączenie, komunikacja. Synchroniczna. Asynchroniczna. Wielowątkowość. Multithreading. Być może, któreś z tych słów już miałeś okazję usłyszeć. W dzisiejszym artykule przyjrzymy się im z bliska i rozwiejemy watpliwości.
Jeden wątek
Wyobraź sobie człowieka, który w danym momencie w czasie jest w stanie zająć się tylko jedną rzeczą. Postępuje zadaniowo. Wkłada naczynia do zmywarki. Jedzie na zakupy i stojąc w kolejce do kasy zajęty jest czekaniem na swoją kolej. Wysyła maila, aby pozyskać informacje i czekając na odpowiedź nie robi nic innego dopóki nie uzyska odpowiedzi i nie zamknie swojego zapytania. Jednym słowem działa jednowątkowo.
W podobny sposób może działać aplikacja. Wyobraź sobie, że wprowadzasz parametry do formularza, na podstawie których mają być odfiltrowane i wyrenderowane na diagramie wyniki. Przetwarzanie danych trwa, aplikacja więc na kilkadziesiąt sekund zawiesza się („freezuje się”) i użytkownik ma wrażenie, że coś poszło nie tak. Tymczasem wszystko jest w jak najlepszym porządku, a aplikacja po prostu czeka. W końcu otrzymuje odpowiedź z serwera, dane są przetworzone i gotowe do wyrenderowania (zwizualizowania) po stronie użytkownika. Działa jednowątkowo, a komunikacja przebiega synchronicznie. Czy byłbyś zadowolony z takiego obrotu spraw?
Wiele watków
Ja jako użytkownik z pewnością nie. Konieczne jest więc rozwiązanie tego w inny sposób. Chcemy, aby komunikacja przebiegała asynchronicznie. Jako aplikacja kliencka chcemy po prostu przekazać parametry i zgłosić serwerowi zapotrzebowanie na przetworzenie danych. Pragniemy otrzymać tak przygotowane dane, aby można je było zwizualizować na wykresie po stronie frontendu. Jednocześnie w międzyczasie nie chcemy czekać. Zamrożenie aplikacji (równoznaczne z niemożliwością nawiązania z nia jakiejkolwiek interakcji) jest niedopuszczalne. Użytkownik powinien móc normalnie z niej korzystać, ewentualnie widzieć content loader/spinner sygnalizujący oczekiwanie. Gdy nadejdzie odpowiedź z backendu możemy na nią zareagować i powrócić do rozpoczętej przez użytkownika akcji – zaprezentować mu wykres z odfiltrowanymi danymi.
Jak osiągnąć taki stan? Przede wszystkim korzystając z wielu wątków, stosując multithreading. Wówczas wątek główny aplikacji nie jest zablokowany czekaniem na odpowiedź z serwera. Może w dalszym ciągu obsługiwać żądania użytkownika, być responsywny. Zapytanie, które wymaga dłuższego oczekiwania na odpowiedź jest wykonywane na innym wątku.
Synchroniczność i asynchroniczność w świecie aplikacji
Synchroniczność moglibyśmy również porównać do rozmowy z konsultantem banku na komunikatorze chatu w czasie rzeczywistym. Wysyłamy wiadomość i oczekujemy na odpowiedź. W trakcie, kiedy konsultant lub (coraz częściej) bot komponuje dla nas odpowiedź jesteśmy nadal w procesie w 100% obecni – czekamy.
Aplikacje działając, generują wiadomości, wysyłają żądania do API i mikroserwisów, wywołują funkcje. Przy komunikacji synchronicznej po wysłaniu takiego żądania software pozostawałby w stanie bezczynności. Kod nie wykonywałby się dalej i trwałoby to do momentu otrzymania odpowiedzi na wysłane żądanie.
W przeciwieństwie do tego przy komunikacji asynchronicznej wysłanie żądania nie powoduje zawieszenia wykonywania kodu źródłowego. Aplikacja działa dalej. Przykładem działania asynchronicznego będzie wbudowany firmware drukarki, który potrafi wysłać komunikat o niskim poziomie toneru jednocześnie nie przerywając drukowania.
Podsumowanie
Reasumując mamy dwa rodzaje komunikacji – synchroniczną i asynchroniczną. Zdając sobie sprawę, że skojarzenie ich z jedno- oraz wielowątkowością może nie być oczywiste, przygotowałam dla Ciebie następujace podsumowanie:
Komunikacja synchroniczna = jednowątkowa ( ang. single thread ):
- (+) Pozwala na przetwarzanie w czasie rzeczywistym
- (+) Zazwyczaj łatwiejsza do śledzenia potencjalnych błędów
- (-) Bywa czasochłonna
- (-) Prowadzi do okresów bezczynności w momencie oczekiwania na wykonanie zadanej czynności/akcji
- (-) Doświadczenia użytkownika mogą być negatywne
Komunikacja asynchroniczna = wielowątkowa ( ang. multithreading ):
- (+) Działanie aplikacji nie ejst blokowane przez wysłane żądania i inne wywołania czekające na swoją kolej
- (+) Wiele czynności może być wykonanych w jednym momencie, co obniża czas oczekiwania użytkowników
- (-) Czasy odpowiedzi nie zawsze są przewidywalne, nie mamy gwarancji tego, że „nie przejdziemy dalej dopóki nie skończymy”
- (-) Trudniejsze śledzenie ewentualnych błędów
Oczywiście zupełnie niezależnie od wiedzy ze świata IT, toczą sie dywagacje na temat tego, w jakim trybie lepiej działa człowiek. Multitasking i przełączanie wątków nie wydają się dobrze służyć naszej produktywności. Zastanówcie się, jak na co dzień Wy działacie- jedno- czy raczej wielowątkowo? 😉
“This blog is a gem! You’ve not only shared valuable insights but also presented them in such a simple and practical way. It makes it easy for readers like me to absorb and apply the information. Thank you for sharing your knowledge.”
“I found this blog extremely helpful. The explanations were clear, the examples were relevant, and the overall tone was very encouraging. It’s evident that you put a lot of effort into making the content both informative and enjoyable to read. Looking forward to more posts!” Microsoft Fabric Training In Hyderabad