Jak używać asyncio w Pythonie

Asynchroniczna funkcja programowania Pythona, w skrócie async, umożliwia pisanie programów, które wykonują więcej pracy, nie czekając na zakończenie niezależnych zadań. asyncioBiblioteka dołączona Python daje narzędzia do asynchronicznie do przetwarzania lub dysk sieciowy I / O bez wszystkiego innego czekać.

asyncio udostępnia dwa rodzaje interfejsów API do obsługi operacji asynchronicznych:  wysokiego poziomu  i  niskiego poziomu . Interfejsy API wysokiego poziomu są najbardziej przydatne i mają zastosowanie do najszerszej gamy aplikacji. Interfejsy API niskiego poziomu są potężne, ale także złożone i używane rzadziej.

W tym artykule skoncentrujemy się na interfejsach API wysokiego poziomu. W poniższych sekcjach omówimy najczęściej używane interfejsy API wysokiego poziomu w  asyncioprogramie i pokażemy, jak można ich używać do typowych operacji obejmujących zadania asynchroniczne. 

Jeśli jesteś zupełnie nowy w asynchronizacji w Pythonie lub możesz odświeżyć informacje o tym, jak to działa, przeczytaj moje wprowadzenie do asynchronizacji Pythona, zanim zaczniesz tutaj.

Uruchamiaj programy i zadania w Pythonie

Oczywiście najczęstszym zastosowaniem programu asynciojest uruchamianie asynchronicznych części skryptu w języku Python. Oznacza to naukę pracy z programami i zadaniami. 

Komponenty asynchroniczne Pythona, w tym programy i zadania, mogą być używane tylko z innymi komponentami asynchronicznymi, a nie z konwencjonalnymi synchronicznymi komponentami Pythona, więc musisz  asyncio wypełnić tę lukę. Aby to zrobić, użyj  asyncio.run funkcji:

import asyncio

async def main ():

print ("Czekam 5 sekund.")

dla _ w zakresie (5):

await asyncio.sleep (1)

print („.”)

print ("Koniec oczekiwania.")

asyncio.run (główna ())

To działa  main()wraz z wszystkimi korektami odpalanymi  main() i czeka na zwrócenie wyniku.

Zasadniczo program w Pythonie powinien mieć tylko jedną  .run() instrukcję, tak jak program w Pythonie powinien mieć tylko jedną  main() funkcję. Async, jeśli jest używany niedbale, może utrudnić odczytanie przepływu sterowania w programie. Posiadanie pojedynczego punktu wejścia do kodu asynchronicznego programu zapobiega tworzeniu się owłosienia.

Funkcje asynchroniczne można również planować jako  zadania lub obiekty, które zawijają procedury i pomagają je uruchamiać.

async def my_task ():

Zrób coś()

task = asyncio.create_task (my_task ())

my_task() jest następnie uruchamiany w pętli zdarzeń, a jego wyniki są przechowywane w pliku  task.

Jeśli masz tylko jedno zadanie, z którego chcesz uzyskać wyniki, możesz  asyncio.wait_for(task) poczekać na zakończenie zadania, a następnie użyć,  task.result() aby pobrać jego wynik. Ale jeśli zaplanowałeś wiele zadań do wykonania i chcesz poczekać, aż  wszystkie  się zakończą, użyj,  asyncio.wait([task1, task2]) aby zebrać wyniki. (Zwróć uwagę, że możesz ustawić limit czasu dla operacji, jeśli nie chcesz, aby działały po określonym czasie).

Zarządzaj pętlą zdarzeń asynchronicznych w Pythonie

Innym typowym zastosowaniem  asyncio jest zarządzanie pętlą zdarzeń asynchronicznych  . Pętla zdarzeń to obiekt, który uruchamia funkcje asynchroniczne i wywołania zwrotne; jest tworzony automatycznie, gdy używasz  asyncio.run(). Zwykle chcesz używać tylko jednej pętli zdarzeń asynchronicznych na program, aby zachować łatwość zarządzania.

Jeśli piszesz bardziej zaawansowane oprogramowanie, takie jak serwer, będziesz potrzebować dostępu do pętli zdarzeń na niższym poziomie. W tym celu możesz „podnieść maskę” i pracować bezpośrednio z elementami wewnętrznymi pętli zdarzeń. Ale w przypadku prostych prac nie musisz tego robić.

Odczytywanie i zapisywanie danych za pomocą strumieni w Pythonie

Najlepsze scenariusze asynchronizacji to długotrwałe operacje sieciowe, w których aplikacja może blokować oczekiwanie na zwrócenie wyniku przez inny zasób. W tym celu  asyncio oferuje strumienie, które są wysokopoziomowymi mechanizmami wykonywania operacji we / wy sieci. Obejmuje to działanie jako serwer dla żądań sieciowych.

asyncio używa dwóch klas  StreamReader i  StreamWriter, do odczytu i zapisu z sieci na wysokim poziomie. Jeśli chcesz czytać z sieci, możesz użyć  asyncio.open_connection() do otwarcia połączenia. Ta funkcja zwraca krotkę   obiektów StreamReader i  StreamWriter, a  do komunikacji należy użyć  metod .read() i  .write().

Aby odbierać połączenia ze zdalnych hostów, użyj  asyncio.start_server(). asyncio.start_server()Funkcji jako argument funkcji zwrotnego,  client_connected_cb, która jest wywołana, kiedy odbiera żądanie. Ta funkcja zwrotna przyjmuje instancje  StreamReader i StreamWriter jako argumenty, więc możesz obsługiwać logikę odczytu / zapisu na serwerze. (Zobacz tutaj przykład prostego serwera HTTP, który korzysta z   biblioteki asynciosterowanej  aiohttp).

Synchronizuj zadania w Pythonie

Zadania asynchroniczne zwykle działają w izolacji, ale czasami chcesz, aby komunikowały się ze sobą. asyncio udostępnia kolejki i kilka innych mechanizmów synchronizacji między zadaniami:

  • Kolejkiasyncio kolejki umożliwiają funkcjom asynchronicznym wyrównywanie obiektów Pythona do wykorzystania przez inne funkcje asynchroniczne - na przykład w celu dystrybucji obciążeń między różnymi rodzajami funkcji na podstawie ich zachowania.
  • Prymitywy synchronizacji : blokady, zdarzenia, warunki i semafory asynciodziałają jak ich konwencjonalne odpowiedniki w Pythonie. 

Jedną rzeczą, o której należy pamiętać w przypadku wszystkich tych metod, jest to, że nie są  one  bezpieczne dla wątków. Nie stanowi to problemu w przypadku zadań asynchronicznych działających w tej samej pętli zdarzeń. Ale jeśli próbujesz udostępniać informacje zadaniom w innej pętli zdarzeń, wątku systemu operacyjnego lub procesie, musisz do tego użyć  threading modułu i jego obiektów.

Ponadto, jeśli chcesz  uruchamiać  programy poza granicami wątku, użyj  asyncio.run_coroutine_threadsafe() funkcji i przekaż pętlę zdarzeń, aby użyć jej jako parametru.

Wstrzymaj program w Pythonie

Innym powszechnym zastosowaniem  asyncioi niedostatecznie omawianym jest czekanie przez jakiś arbitralny czas wewnątrz programu. Nie możesz time.sleep() do tego użyć  , albo zablokujesz cały program. Zamiast tego użyj  asyncio.sleep(), co pozwala innym programom kontynuować działanie.

Użyj asynchronii niższego poziomu w Pythonie

Wreszcie, jeśli myślisz, że aplikacja, którą budujesz, może wymagać asynciokomponentów niższego poziomu, rozejrzyj się, zanim zaczniesz kodować: istnieje duża szansa, że ​​ktoś już zbudował bibliotekę Pythona z asynchronicznym działaniem, która robi to, czego potrzebujesz.

Na przykład, jeśli potrzebujesz asynchronicznego zapytania DNS, sprawdź  aiodns bibliotekę, aw przypadku asynchronicznych sesji SSH jest  asyncSSH. Wyszukaj w PyPI słowo kluczowe „async” (oraz inne słowa kluczowe związane z zadaniami) lub poszukaj pomysłów na ręcznie przygotowanej liście Awesome Asyncio.