Programowanie asynchroniczne: rodzaje, klasyfikacja, zasady programowania, pojęcie, znaczenie i zastosowanie

Programowanie asynchroniczne (AS) to forma programowania współbieżnego, która pozwala jednostce strukturalnej systemu pracować oddzielnie od głównego wątku aplikacji. Kiedy zadanie jest wykonane, powiadamia główny wątek, czy zadanie zostało zakończone, czy nie. Takie programowanie jest korzystne, ponieważ zwiększa obsługiwaną przepustowość, co czyni je atrakcyjnym, biorąc pod uwagę rosnące zapotrzebowanie Internetu na wysoce skalowalne systemy.

Modele programowania asynchronicznego

W celu obsługi ciągłości wyniku operacji nieblokujących po ich zakończeniu stworzono różne modele AP. Ich zalety są oceniane pod względem tego, jak bardzo pozwalają na uzyskanie schematu najbardziej zbliżonego do sekwencyjnego.

Modele programowania asynchronicznego

Rodzaje modeli AP:

  1. Model etapu kontynuacji. Jest to najczęściej używany model asynchroniczny w Node JS. Każda funkcja otrzymuje informację o tym, jak powinna obsłużyć wynik sukcesu lub błędu w operacji.
  2. Model zdarzeń - model zdarzeń, wykorzystuje architekturę sterowaną zdarzeniami, która pozwala operacjom nieblokującym zgłaszać swoje zakończenie na znak sukcesu lub porażki, wymaga korelacji do synchronizacji.
  3. Model obietnicy - model obietnicy wyjaśnia wartości zwrotne operacji nieblokujących niezależnie od momentu, w którym uzyskano określone wartości sukcesu lub porażki.
  4. Model generatora. Generatory służą do tymczasowego zwrócenia kontroli do programu wywołującego, a następnie powrotu do podprogramu poprzez przywrócenie stanu w punkcie, w którym jego wykonanie zostało zakończone.

Zasady architektoniczne Node

Chociaż Node JS otrzymał ostatnio ostrą krytykę za wykorzystanie pętli obliczeniowych ze względu na jego jednowątkowe środowisko, jego filozofia, oparta na trzech silnych zasadach architektonicznych, pozostaje w modzie.

JavaScript jest z natury asynchroniczny, podobnie jak Node. Platforma dla uruchomienie JavaScript po stronie serwera, Node.js został wprowadzony w 2009 roku z asynchronicznym modelem I/O sterowanym zdarzeniami, dzięki czemu jest wydajny i skalowalny.

Czat jest najbardziej typowym przykładem aplikacji Node dla wielu użytkowników.w czasie rzeczywistym js. Począwszy od IRC dla wielu własnościowych i otwartych protokołów na niestandardowych portach, stało się możliwe wdrożenie wszystkiego w nowoczesnych Noje.js z WebSockets działającymi domyślnie na tym samym porcie 80, który nasłuchuje nowych wiadomości wysyłanych przez ich klientów. Po stronie klienta znajduje się strona HTML z kilkoma skonfigurowanymi handlerami, jeden dla przycisku "Wyślij", który wybiera wiadomość i wysyła ją do WebSocket, oraz drugi, który nasłuchuje wiadomości przychodzących do klienta. Oczywiście prosty i podstawowy model, ale oparty na innej wariancji złożoności.

Nieaktywny model, którego Node JS używa w API do obsługi programowania asynchronicznego, to krok kontynuacji. Każda operacja nieblokująca otrzymuje jako ostatni parametr funkcję, która zawiera logikę kontynuacji. Zostanie on wywołany po zakończeniu operacji, zarówno w celu przetworzenia wyników w przypadku sukcesu, jak i w celu wyeliminowania błędów. Funkcja kontynuacji umożliwia określenie sposobu kontynuacji operacji blokowania po zakończeniu operacji.

Zasady architektoniczne Node

Sekwencyjne sterowanie przepływem

Aby kontynuować tworzenie sekwencyjnych wątków wykonawczych w ramach tego modelu, konieczne jest łańcuchowanie każdej kolejnej funkcji jako rozszerzenie poprzedniej, gdzie wyniki będą obsługiwane w przypadku sukcesu lub porażki. Prowadzi to do diagonalizacji kodu, która została nazwana piramidą piekła (callback hell), ze względu na brak praktycznej możliwości zarządzania, tak długo jak liczba łańcuchów sekwencyjnych rośnie minimalnie.

Sekwencyjne sterowanie przepływem

Paralelizacja - asynchroniczne wykonanie operacji nieblokujących następuje natychmiast, ponieważ jej proste wywołanie jest z definicji wykonywane w tle. Przekształcenie operacji blokujących w nieblokujące wymaga małego procesu enkapsulacji, który wykonuje operację w tle.

Asynchroniczne wykonywanie operacji nieblokujących

Synchronizacja funkcji kontynuacji

Wymaga łańcucha na końcu każdej równoległej sekwencji funkcji zakończenia, która stosuje określoną logikę tylko po, jak zostanie potwierdzone, że wszystkie równoległe gałęzie są zakończone. Do realizacji tej kontroli wykorzystywane są schematy oparte na licznikach.

Synchronizacja funkcji kontynuacji

Przykład z kontynuatorami:

  1. Równoległość, pętla pozwala na wykonanie wszystkich par read-count w sposób nieblokujący.
  2. Sekwencyjnie, każda para odczytów jest odczytywana przez krok funkcji kontynuacji.
  3. Synchronizacja, każda równoległa gałąź otrzymuje ostatnią kontynuację, która wykonuje logikę zakończenia, gdy tylko wszystkie gałęzie zostaną zakończone.

Biblioteki kontynuujące

Jest wiele bibliotek, które mogą pomóc ułatwić sobie życie dla programistów pracujących z modelem AP. Niektóre z nich związane są nie tylko z AP, ale także z paradygmatem funkcjonalnym, który wynika z faktu, że mechanizmy egzekwowania połączeń są zasadniczo funkcjonalnymi świadczeniami.

Rodzaje bibliotek:

  1. Async jest prawdopodobnie najbardziej znaną i najczęściej używaną biblioteką do asynchronicznego programowania opartego na kontynuacji. Oferuje różne metody kontroli przepływu dla funkcji nieblokujących.
  2. Join - jest implementacją metody synchronizacji występującej w innych językach, takich jak C i praca z wątkami. Może być również używany w obietnicach, choć w tym przypadku jego użycie jest mniej istotne.
  3. Fn.js jest doskonałą biblioteką, która implementuje różne metody kontroli funkcjonalnej. Jego praktyczne zastosowanie w tym kontekście wynika z możliwości, jakie daje generowanie funkcji nieblokujących i stosowanie walidacji.

Zalety i wady

Programowanie asynchroniczne oparte na continuatorach jest dobrym rozwiązaniem w sytuacjach z prostą logiką kontroli przepływu. Zwykle odnosi się to do programów w Node JS, które pozwalają zdefiniować nieblokującą odpowiedź na przychodzące żądania.

Korzyści dla modelu:

  1. Proste wzory żądań i odpowiedzi.
  2. Spójność ze schematami programowania funkcjonalnego.
  3. Łatwy do zrozumienia jako mechanizm koncepcyjny.

Wady:

  1. Gdy logika sterowania nie jest wystarczająco zaprojektowana, proces staje się bardziej złożony, co skutkuje kodem z rozproszoną logiką funkcjonalną, który jest trudny do odczytania, zrozumienia i utrzymania.
  2. Trudności w definiowaniu logiki sterowania przepływem.
  3. Zaawansowane mechanizmy synchronizacji.
  4. Logika sterowania jest przypisana do każdej nie blokującej się gałęzi.

Model sterowany zdarzeniami

Zdarzenie jest sygnałem w ekosystemie biznesowym. Anatomicznie składają się one zazwyczaj z typu, znacznika czasu oraz zestawu danych opisujących kontekst, w którym doszło do zdarzenia. Architektura zdarzeń (EDA) zapewnia mechanizm łączenia klientów i dostawców w relacji 1: N i z nominalnym odsprzężeniem. Jednym z wielu jego zastosowań jest rozwiązywanie problemów związanych z asynchronicznym przetwarzaniem danych.

W scentralizowanych, sterowanych zdarzeniami architekturach istnieje centralny mediator magistrali komunikacyjnej, który jest odpowiedzialny za zapewnienie, że proces rejestracji klientów nasłuchujących i wyzwalania powiadomień na żądanie do dostawców jest wydajny. Mechanizm ten pozwala na uzyskanie przepustowości N:N, a schemat ten nazywany jest wzorcem PUB/SUB.

W rozproszonych architekturach sterowanych zdarzeniami, każdy dostawca jest odpowiedzialny za zarządzanie subskrypcjami swoich klientów i za wysyłanie powiadomień, gdy wystąpi zdarzenie. Mechanizm komunikacji jest również nominalnie oddzielny, ale zazwyczaj liczba dostawców i klientów wynosi 1:N. Ten wzór odpowiada obserwowanemu wzorcowi lub źródłom zdarzeń w żargonie Node JS.

Abstrakcja obliczeniowa: obietnica

Abstrakcja obliczeniowa: Obietnica

Obietnica jest abstrakcją obliczeniową, która reprezentuje zobowiązanie ze strony wywołanej operacji nieblokującej do dostarczenia odpowiedzi do programu wywołującego, gdy wynik jest odbierany po zakończeniu. Obietnica jest obiektem, który zapewnia dwie metody włączenia logiki przetwarzania w przypadku sukcesu lub porażki.

Odpowiadają one na prosty cykl życia, który musisz znać, aby z nimi pracować. Zasadnicza wartość obietnicy leży w dwóch zasadach. Po pierwsze, logika do przetwarzania w przypadku sukcesu lub porażki jest stosowana tylko raz. A po drugie, logika sukcesu lub porażki jest gwarantowana do wykonania, nawet jeśli obietnica zostanie rozwiązana przed, podobnie jak wprowadzone przez jej kierowców. Jeśli jest to wymagane, obietnica czeka na swoich opiekunów, asynchronicznie Programowanie w języku JavaScript.

Istnieją kilka metod otrzymują obietnice, które można zidentyfikować jako wzorce konstrukcyjne pojawiające się okresowo, gdy ten model jest używany. Definicja ES6 zawiera obietnice i Node JS w wersji 0.12 ma wsparcie tej specyfikacji. Ponadto istnieje kilka bibliotek, które implementują model obietnicy. W celu uzyskania porównawczego punktu odniesienia zdefiniowano standard Promises A+, który zarządza wszystkimi wdrożeniami za pomocą dostępnych wówczas.

Programowanie synchroniczne i asynchroniczne

Zaleca się stosowanie AP JavaScript, ładując do niego wszystkie swoje tagi i kod dostawcy. Zapewnia to najlepszą kompatybilność z największą liczbą sprzedawców. Takie umieszczenie daje wszystkim znacznikom dostawców największą szansę na zakończenie śledzenia, zanim odwiedzający zostanie przeniesiony na kolejną stronę.

Ładowanie synchroniczne występuje wtedy, gdy przeglądarka musi przerwać renderowanie strony, aby zakończyć działanie kodu JavaScript. Jeśli wykryje synchroniczny tag JS, blokuje wyświetlanie strony do czasu zakończenia kodu. Jest to analogiczne do wolno poruszającej się ciężarówki na jednopasmowej drodze, która spowalnia ruch za sobą. Nowoczesne strony internetowe odeszły od tej metody, ponieważ stwarza ona bezpośrednie ryzyko opóźnienia czasu ładowania strony.

Wadą tej metody jest to, że cała strona jest zablokowana przed uruchomieniem, dopóki znacznik nie zostanie w pełni załadowany. I chociaż dostawcy tagów mają umowy o poziomie usług na czas ich dostarczania, kilka czynników może wpłynąć na wydajność. Należą do nich wolne czasy reakcji związane z dostawcami, utrzymywanie niepotrzebnych serwerów aplikacji w hybrydowym modelu klient-serwer oraz powolny ruch internetowy. Jeśli użytkownik ładuje tagi synchronicznie, warto zadbać o to, by dostawca miał czas reakcji 100 milisekund (ms) lub szybszy.

Programowanie synchroniczne i asynchroniczne poprzez API to interfejsy programowania aplikacji, które zwracają dane do zapytań natychmiast lub odpowiednio później. Synchroniczne i asynchroniczne interfejsy API zapewniają sposób na natychmiastowe lub zaplanowane żądania zasobów, danych lub usług, gdy są dostępne. Nowoczesna metoda, przyjętym dla stron internetowych jest asynchroniczne ładowanie tagów.

W tej metodzie kod JavaScript jest przetwarzany równolegle z resztą zawartości strony. Oznacza to, że nawet jeśli znacznik dostawcy będzie wolno reagował lub ładował się, nie spowolni to reszty strony. Stosując to podejście, nie tylko można oddzielić ładowane tagi JavaScript niezależnie od siebie, ale metoda asynchroniczna minimalizuje wpływ ładowania zewnętrznych plików JS na proces renderowania strony.

Zrozumienie i profilowanie C #

Zrozumienie i profilowanie C #

Microsoft i społeczność .NET znacznie uprościł AS, implementując asynchroniczne oczekiwanie w C #. Najnowsze wersje ASP.NET aktywnie wykorzystuje je do poprawy wydajności. Wiele narzędzi do monitorowania wydajności i profilowania próbuje utrzymać i wizualizować wydajność asynchronicznego programowania 1C. Produkty Stackify Prefix & Retrace mają doskonałe wsparcie dla aplikacji wykorzystujących C # async await. Po pierwsze, musimy zrozumieć, jak właściwie działa kod, który używa async awai" i HttpClient jako przykład.

Zrozumienie i profilowanie C #

Używając ILSpy, możesz zobaczyć, jak kompilator konwertuje ten kod na maszynę AsyncState. Skończony automat wykonuje cały złożony kod pod przykrywką, pozwalając programistom pisać asynchroniczny kod.

HttpClient jako przykład

Profilowanie programowania asynchronicznego w C 5 0 jest trudne, ponieważ przekracza wątki. Tradycyjnie, metoda i wszystkie jej podrzędne wywołania metod występują w tym samym wątku. Dzięki temu łatwiej jest zrozumieć relacje między metodami rodzica i dziecka. Z kodem asynchronicznym to inna historia. Metoda nadrzędna działa w jednym wątku. Gdy rozpoczyna się operacja I/O, kod w tym wątku kończy się. Po zakończeniu operacji I/O, kod kontynuuje pracę w nowym wątku. Łączenie kodu między tymi wątkami w ramach większej transakcji jest dość skomplikowane.

AIOHTTP: serwer-klient dla asyncio

Aiohttp - pozwala użytkownikom na tworzenie asynchronicznych serwerów i klientów. Pakiet do programowania asynchronicznego aiohttp działa zarówno dla klienta jak i serwera gniazd internetowych. Dokumentacja w tym przykładzie aiohttp jest używany do przechwytywania strony HTML.

AIOHTTP: serwer-klient dla asyncio

Ten przykład pokazuje jak przesłać jeden lub więcej plików, możliwe jest również pobieranie plików poprzez. Określa kilka nowych elementów, takich jak asynctimeout. To tworzy menedżera kontekstu czasu oczekiwania. Poniższy kod tworzy asynchroniczną pętlę synchroniczną i używa jej jako funkcja główna.

Utwórz obiekt Client Session w głównej funkcji programowania asynchronicznego, a także funkcję współprogramującą, która zbiera adresy URL wszystkiego, co jest potrzebne obciążenie. W pobieraniu coroutine tworzy menedżera kontekstu, który działa przez około X sekund. Po upływie tej liczby sekund menedżer kontekstu X kończy pracę. Następnie użyj funkcji get () sesji, która znajduje obiekt odpowiedzi.

Kiedy programista tworzy atrybut content obiektu odpowiedzi, zwraca aiohttp. StreamReader, który pozwala użytkownikowi na pobranie pliku o dowolnym rozmiarze. Po odczytaniu pliku jest on zapisywany na dysku lokalnym. Następnie użyj funkcji response (), aby zakończyć przetwarzanie odpowiedzi. Zgodnie z dokumentacją domyślnie wywołuje release (). Jednak asynchroniczne programowanie w Pythonie jest wyraźnie lepsze. Najlepiej pozostawić tę funkcję, aby zapobiec dalszym problemom. Jest tutaj jedna sekcja, która blokuje sekcję kodu do zapisania na dysku, a kod pozostaje zablokowany. Używanie aiohttp - prawdziwy sposób Usprawnienie przepływu pracy, gdzie użytkownicy nie muszą tracić czasu na tworzenie serwera, wgrywanie referencji i pisanie plików asynchronicznych, co skraca czas tworzenia projektu.

Programowanie asynchroniczne osiąga większą wydajność w oprogramowaniu, ponieważ żaden przepływ wykonawczy nie jest blokowany przez długie procesy lub interakcje użytkownika, zarówno dla rozwoju aplikacji Node, jak i przeglądarki.

Artykuły na ten temat