3 koraka do Python async remonta

Python je jedan od mnogih jezika koji podržavaju neki način pisanja asinkronih programa - programa koji se slobodno prebacuju između više zadataka, a svi se izvode istovremeno, tako da niti jedan zadatak ne zadržava napredak ostalih.

Šanse su, međutim, da ste uglavnom napisali sinkrone programe Python - programe koji istodobno rade samo jednu stvar, čekajući da se svaki zadatak završi prije pokretanja drugog. Prelazak na asinkronizaciju može biti nezgodan, jer zahtijeva učenje ne samo nove sintakse, već i novih načina razmišljanja o nečijem kodu. 

U ovom ćemo članku istražiti kako se postojeći, sinkroni program može pretvoriti u asinkroni. To uključuje više od pukog ukrašavanja funkcija asinkrom sintaksom; također zahtijeva drugačije razmišljanje o tome kako se naš program izvodi i odlučivanje je li async uopće dobra metafora za ono što radi. 

[Također na: Saznajte Python savjete i trikove iz Smart Python videa Serdara Yegulalpa]

Kada koristiti async u Pythonu

Python program je najprikladniji za asinkronizaciju kada ima sljedeće značajke:

  • Pokušava učiniti nešto što je uglavnom vezano I / O-om ili čekanjem da se završi neki vanjski postupak, poput dugotrajnog mrežnog čitanja.
  • Pokušava odraditi jednu ili više takvih zadataka odjednom, a istovremeno možda i rukuje korisničkim interakcijama.
  • Zadaci u pitanju nisu računski teški.

Python program koji koristi navoja navoja obično je dobar kandidat za korištenje async-a. Teme u Pythonu su suradničke; po potrebi ustupaju jedni drugima. Asinhroni zadaci u Pythonu rade na isti način. Osim toga, async nudi određene prednosti u odnosu na niti:

  • async/ awaitSintaksa olakšava identifikaciju asinkroni dijelove svog programa. Suprotno tome, često je teško na prvi pogled reći koji se dijelovi aplikacije izvode u niti. 
  • Budući da asinkroni zadaci dijele istu nit, svim podacima kojima pristupaju automatski upravlja GIL (Pythonov izvorni mehanizam za sinkronizaciju pristupa objektima). Niti često zahtijevaju složene mehanizme za sinkronizaciju. 
  • Async zadacima je lakše upravljati i otkazati ih nego nitima.

Korištenje async-a se ne preporučuje ako vaš Python program ima ove karakteristike:

  • Zadaci imaju visoku računsku cijenu - npr. Rade veliko usitnjavanje brojeva. Najbolje je riješiti težak računalni posao multiprocessingkoji vam omogućuje da svakom zadatku posvetite cijelu hardversku nit.
  • Zadaci nemaju koristi od međusobnog prepletanja. Ako svaki zadatak ovisi o zadnjem, nema smisla tjerati ih da rade asinkrono. Međutim, ako program uključuje  skupove serijskih zadataka, svaki skup možete pokrenuti asinkrono.

Korak 1: Identificirajte sinkroni i asinkroni dio vašeg programa

Python async kôd moraju pokrenuti i njime upravljati sinkroni dijelovi vaše Python aplikacije. U tu svrhu vaš prvi zadatak pri pretvaranju programa u async je povlačenje linije između sinkroniziranih i async dijelova vašeg koda.

U našem prethodnom članku o asinkronizaciji koristili smo aplikaciju za struganje weba kao jednostavan primjer. Asinkroni dijelovi koda su rutine koje otvaraju mrežne veze i čitaju s web mjesta - sve ono što želite preplesti. Ali dio programa koji pokreće sve to nije asinkroniziran; lansira asinkrne zadatke, a zatim ih graciozno zatvara kad završe.

Također je važno odvojiti svaku potencijalno  blokirajuću operaciju od async i zadržati je u sinkronizacijskom dijelu svoje aplikacije. Čitanje korisničkog unosa s konzole, na primjer, blokira sve, uključujući petlju async događaja. Stoga želite rukovati korisničkim unosom bilo prije pokretanja asinkrenih zadataka ili nakon što ih dovršite. (Moguće je asinhrono rukovati korisničkim unosom putem višestruke obrade ili navoja, ali to je napredna vježba u koju ovdje nećemo ulaziti.)

Nekoliko primjera operacija blokiranja:

  • Ulaz konzole (kao što smo upravo opisali).
  • Zadaci koji uključuju veliku upotrebu CPU-a.
  • Koristeći time.sleepza forsiranje stanke. Imajte na umu da možete spavati u funkciji asinkronizacije koristeći je asyncio.sleepkao zamjenu za time.sleep.

Korak 2: Pretvorite odgovarajuće funkcije sinkronizacije u funkcije asinkronizacije

Jednom kada saznate koji će se dijelovi programa izvoditi asinkrono, možete ih razdijeliti na funkcije (ako to već niste učinili) i pretvoriti u asinkrone funkcije s asyncključnom riječi. Tada ćete morati dodati kôd u sinkroni dio aplikacije da biste pokrenuli asinkroni kôd i po potrebi prikupili rezultate iz njega.

Napomena: Morat ćete provjeriti lanac poziva svake funkcije koju ste učinili asinkronom i osigurati da ne pozivaju potencijalno dugotrajnu ili blokirajuću operaciju. Async funkcije mogu izravno pozivati ​​sync funkcije, a ako ta sync funkcija blokira, onda to čini i async funkcija koja je poziva.

Pogledajmo pojednostavljeni primjer kako pretvorba sinkronizacije u asinkronu može funkcionirati. Evo našeg programa "prije":

def a_function (): # neka radnja kompatibilna s asinkronom sinkronizacijom koja traje neko vrijeme def another_function (): # neka funkcija sinkronizacije, ali ne i ona koja blokira def do_stuff (): a_function () another_function () def main (): za _ u dometu (3): do_stuff () glavni () 

Ako želimo da se tri instance do_stuffizvršavaju kao asinkroni zadaci, moramo pretvoriti do_stuff (i potencijalno sve što dotakne) u asinkroni kod. Evo prvog prolaska kod pretvorbe:

import asyncio async def a_function (): # neka async-kompatibilna radnja koja traje neko vrijeme def another_function (): # neka funkcija sinkronizacije, ali ne i blokiranje jedne async def do_stuff (): pričekajte a_function () another_function () async def main ( ): zadaci = [] za _ u dometu (3): zadaci.dodaj (asyncio.create_task (do_stuff ())) čeka asyncio.gather (zadaci) asyncio.run (glavni ()) 

Zabilježite promjene koje smo napravili  main. Sada main koristi asyncioza pokretanje svake instance do_stuffkao istodobni zadatak, a zatim čeka rezultate ( asyncio.gather). Također smo pretvorili a_functionu async funkciju, jer želimo da se svi primjeri a_functionpokreću jedna pored druge, kao i sve druge funkcije koje trebaju async ponašanje.

Ako bismo željeli ići korak dalje, mogli bismo također pretvoriti another_functionu async:

async def another_function (): # neka funkcija sinkronizacije, ali ne i blokiranje async def do_stuff (): await a_function () await another_function () 

Međutim, stvaranje  another_function asinkronog bilo bi pretjerano, jer (kao što smo napomenuli) ne čini ništa što bi moglo blokirati napredak našeg programa. Također, ako bi se zvao bilo koji sinkroni dio našeg programa  another_function, morali bismo ih pretvoriti i u asinkronizaciju, što bi naš program moglo zakomplicirati nego što treba.

Korak 3: Temeljito testirajte svoj Python async program

Svaki asinhronizirani program treba testirati prije nego što krene u proizvodnju kako bi se osiguralo da radi kako se očekuje.

Ako je vaš program skromne veličine - recimo, nekoliko desetaka redaka ili tako nešto - i ne treba vam cjelovit testni paket, tada ne bi trebalo biti teško provjeriti radi li kako je predviđeno. Ako pretvorite program u async kao dio većeg projekta, gdje je testni paket standardni uređaj, ima smisla napisati unit testove za async i sync komponente.

Oba glavna testna okvira u Pythonu sada imaju neku vrstu async podrške. Pythonov vlastiti  unittest okvir uključuje test slučajeve za async funkcije i pytestnudi ponude  pytest-asyncioza iste krajeve.

Finally, when writing tests for async components, you’ll need to handle their very asynchronousness as a condition of the tests. For instance, there is no guarantee that async jobs will complete in the order they were submitted. The first one might come in last, and some might never complete at all. Any tests you design for an async function must take these possibilities into account.

How to do more with Python

  • Get started with async in Python
  • How to use asyncio in Python
  • How to use PyInstaller to create Python executables
  • Cython tutorial: How to speed up Python
  • How to install Python the smart way
  • How to manage Python projects with Poetry
  • How to manage Python projects with Pipenv
  • Virtualenv and venv: Python virtual environments explained
  • Python virtualenv and venv do’s and don’ts
  • Python threading and subprocesses explained
  • How to use the Python debugger
  • Kako koristiti timeit za profiliranje Python koda
  • Kako koristiti cProfile za profiliranje Python koda
  • Kako pretvoriti Python u JavaScript (i natrag)