Kako koristiti asyncio u Pythonu

Pythonova funkcionalnost asinkronog programiranja, ili skraćeno async, omogućuje vam pisanje programa koji će obaviti više posla ne čekajući da samostalni zadaci završe. asyncioKnjižnica uključena u Pythonu daje vam alate da koristite asink za obradu disk ili mrežni ulaz / izlaz bez sve ostalo pričekati.

asyncio pruža dvije vrste API-ja za rješavanje asinkronih operacija:  visoku  i  nisku razinu . API-ji visoke razine najčešće su najkorisniji i primjenjivi su na najrazličitije programe. API-ji niske razine moćni su, ali i složeni te se rjeđe koriste.

U ovom ćemo se članku usredotočiti na API-je na visokoj razini. U odjeljcima u nastavku proći ćemo kroz najčešće korištene API-je na visokoj razini  asyncioi pokazati kako se oni mogu koristiti za uobičajene operacije koje uključuju asinkrone zadatke. 

Ako ste potpuno novi u async u Pythonu ili biste mogli upotrijebiti osvježivač kako to radi, pročitajte moj uvod u Python async prije nego što ovdje zaronite.

Pokrenite programe i zadatke u Pythonu

Naravno, najčešće se koristi za asynciopokretanje asinkronih dijelova vaše Python skripte. To znači naučiti raditi s programima i zadacima. 

Pythonove async komponente, uključujući potprograme i zadatke, mogu se koristiti samo s drugim async komponentama, a ne i s konvencionalnim sinkronim Pythonom, pa morate  asyncio premostiti prazninu. Da biste to učinili, koristite  asyncio.run funkciju:

uvoziti asyncio

async def main ():

ispis ("Čekanje 5 sekundi.")

za _ u rasponu (5):

await asyncio.sleep (1)

ispis (".")

ispis ("Završeno čekanje.")

asyncio.run (glavni ())

To se pokreće  main(), zajedno sa svim potprogramima  main() , i čeka da se rezultat vrati.

Općenito, program Python trebao bi imati samo jednu  .run() izjavu, kao što bi program Python trebao imati samo jednu  main() funkciju. Async, ako se koristi nepažljivo, može otežati čitanje kontrolnog toka programa. Postojanje jedne ulazne točke u asinhroni kod programa sprečava stvari da postanu dlakavi.

Async funkcije također se mogu rasporediti kao  zadaci ili kao objekti koji omotavaju programe i pomažu u njihovom izvođenju.

async def my_task ():

učini nešto()

zadatak = asyncio.create_task (moj_zadatak ())

my_task() se zatim izvodi u petlji događaja, a rezultati se pohranjuju u  task.

Ako imate samo jedan zadatak iz kojeg želite dobiti rezultate, možete  asyncio.wait_for(task) pričekati da se zadatak završi, a zatim upotrijebite  task.result() za dohvaćanje njegovog rezultata. Ali ako ste zakazali izvršavanje brojnih zadataka i želite pričekati da se  svi  završe, upotrijebite  asyncio.wait([task1, task2]) za prikupljanje rezultata. (Imajte na umu da možete postaviti vremensko ograničenje za operacije ako ne želite da proteknu određeno vrijeme.)

Upravljanje async petljom događaja u Pythonu

Sljedeća uobičajena upotreba za  asyncio je upravljanje petljom async  događaja . Petlja događaja je objekt koji pokreće asinkrne funkcije i povratne pozive; automatski se stvara kada upotrebljavate  asyncio.run(). Općenito želite koristiti samo jednu petlju asinkronog događaja po programu, kako bi se stvari održale upravljivima.

Ako pišete napredniji softver, poput poslužitelja, trebat će vam pristup petlje događaja niže razine. U tu svrhu možete "podići napa" i izravno raditi s unutarnjim dijelovima petlje događaja. Ali za jednostavne poslove nećete trebati.

Čitanje i pisanje podataka s streamovima u Pythonu

Najbolji scenariji za async su dugotrajne mrežne operacije, gdje aplikacija može blokirati čekanje da neki drugi resurs vrati rezultat. U tu svrhu  asyncio nudi streamove, koji su mehanizmi visoke razine za izvođenje mrežnih I / O. To uključuje djelovanje kao poslužitelj za mrežne zahtjeve.

asyncio koristi dvije klase  StreamReader i  StreamWriterza čitanje i pisanje s mreže na visokoj razini. Ako želite čitati s mreže, upotrijebite  asyncio.open_connection() za otvaranje veze. Ta funkcija vraća skup  StreamReader i  StreamWriter objekata, a vi biste koristili  .read() i  .write() metode na svakom za komunikaciju.

Za primanje veza od udaljenih hostova koristite  asyncio.start_server(). asyncio.start_server()Funkcija uzima kao argument funkciju povratnog poziva,  client_connected_cbkoja se zove kad god primi zahtjev. Ta funkcija povratnog poziva uzima instance  StreamReader i StreamWriter kao argumente, tako da možete rukovati logikom čitanja / pisanja za poslužitelj. (Pogledajte ovdje primjer jednostavnog HTTP poslužitelja koji koristi   knjižnicu asyncio-driven  aiohttp.)

Sinkronizirajte zadatke u Pythonu

Asinkroni zadaci obično se izvode izolirano, ali ponekad ćete poželjeti da međusobno komuniciraju. asyncio pruža redove čekanja i nekoliko drugih mehanizama za sinkronizaciju između zadataka:

  • Redoviasyncio redovi omogućuju asinhrone funkcije da poredaju Python objekte kako bi ih konzumirale druge asinkre funkcije - na primjer, za raspodjelu radnog opterećenja između različitih vrsta funkcija na temelju njihovog ponašanja.
  • Primitivi za sinkronizaciju : brave, događaji, uvjeti i semafori u asyncioradu poput njihovih uobičajenih Python kolega. 

Kod svih ovih metoda morate imati na umu da one  nisu  zaštićene od niti. Ovo nije problem za asinkrone zadatke koji se izvode u istoj petlji događaja. Ali ako pokušavate dijeliti informacije sa zadacima u drugoj petlji događaja, OS niti ili procesu, morat ćete upotrijebiti  threading modul i njegove objekte za to.

Dalje, ako želite  pokrenuti  programe preko granica niti, upotrijebite  asyncio.run_coroutine_threadsafe() funkciju i proslijedite petlju događaja da biste je koristili kao parametar.

Pauzirajte programsku podršku u Pythonu

Još jedna uobičajena upotreba  asyncio, o kojoj se nedovoljno raspravlja, čeka neko proizvoljno vrijeme unutar koroutine. Ne možete koristiti  time.sleep() za ovo ili ćete blokirati cijeli program. Umjesto toga, upotrijebite  asyncio.sleep(), što omogućuje ostalim programima da se nastave izvoditi.

Upotrijebite asinkronizaciju niže razine u Pythonu

Konačno, ako mislite da aplikacija koja gradite možda zahtijeva asynciokomponente niže razine, pogledajte oko sebe prije nego što započnete s kodiranjem: Postoji velika šansa da je netko već izgradio async-powered Python knjižnicu koja radi ono što trebate.

Na primjer, ako trebate async DNS upite, provjerite  aiodns knjižnicu, a za async SSH sesije postoji  asyncSSH. Pretražite PyPI po ključnoj riječi "async" (plus ostale ključne riječi povezane sa zadatkom) ili potražite ideje za ručno kurirani Awesome Asyncio popis.