Programavimas

Pradėkite naudoti „Python“ asinchronizavimą

Asinchroninis programavimas arba asinchroninis trumpai tariant, yra daugelio šiuolaikinių kalbų bruožas, leidžiantis programai žongliruoti keliomis operacijomis nelaukiant ir neužkabinant nė vieno iš jų. Tai protingas būdas efektyviai valdyti tokias užduotis kaip tinklo ar failų įvestis / išvestis, kai didžioji dalis programos laiko praleidžiama laukiant užduoties pabaigos.

Apsvarstykite žiniatinklio grandymo programą, kuri atidaro 100 tinklo jungčių. Galėtumėte atidaryti vieną ryšį, palaukti rezultatų, tada atidaryti kitą ir laukti rezultatų ir pan. Didžioji laiko dalis, kurią programa vykdo, praleidžiama laukiant tinklo atsakymo, o ne dirbant faktinį darbą.

„Async“ suteikia jums efektyvesnį metodą: atidarykite visus 100 ryšių vienu metu, tada perjunkite kiekvieną aktyvų ryšį, kai jie pateikia rezultatus. Jei vienas ryšys rezultatų neduoda, pereikite prie kito ir t. T., Kol visi ryšiai grąžins savo duomenis.

„Async“ sintaksė dabar yra standartinė „Python“ funkcija, tačiau ilgamečiams „Pythonistams“, įpratusiems daryti vieną dalyką vienu metu, gali kilti sunkumų apgaubiant galvą. Šiame straipsnyje mes ištirsime, kaip asinchroninis programavimas veikia „Python“ ir kaip jį naudoti.

Atminkite, kad jei norite naudoti „Python“ asinchronizavimą, geriausia naudoti „Python 3.7“ arba „Python 3.8“ (naujausią šio rašymo versiją). Mes naudosime „Python“ asinchroninės sintaksės ir pagalbininkų funkcijas, apibrėžtas tose kalbos versijose.

Kada naudoti asinchroninį programavimą

Apskritai geriausia naudoti asinchroninį laiką, kai bandote atlikti šiuos bruožus turinčius darbus:

  • Darbui atlikti reikia daug laiko.
  • Vėlavimas apima I / O (disko ar tinklo) operacijų laukimą, o ne skaičiavimą.
  • Darbas apima daug įvesties / išvesties operacijų vienu metu, arba viena ar daugiau įvesties / išvesties operacijų, kai bandote atlikti kitas užduotis.

„Async“ leidžia lygiagrečiai nustatyti kelias užduotis ir efektyviai jas kartoti, neužblokuojant likusios programos.

Keletas užduočių, kurios gerai veikia su asinchronizavimu, pavyzdžių:

  • Žiniatinklio grandymas, kaip aprašyta aukščiau.
  • Tinklo paslaugos (pvz., Žiniatinklio serveris ar pagrindas).
  • Programos, kurios koordinuoja rezultatus iš kelių šaltinių, kurių vertėms grąžinti reikia daug laiko (pavyzdžiui, vienu metu atliekamos duomenų bazės užklausos).

Svarbu pažymėti, kad asinchroninis programavimas skiriasi nuo daugialypio ar daugiaprocesinio. Visos asinchroninės operacijos vykdomos ta pačia gija, tačiau prireikus viena kitai pasiduoda, todėl asinchronizavimas yra efektyvesnis nei daugelio rūšių užduočių sriegimas ar daugiaprocesinis apdorojimas. (Daugiau apie tai žemiau.)

„Python“ asinchroninislaukti ir asyncio

Python neseniai pridėjo du raktinius žodžius, asinchroninis ir laukti, skirtas asinchroninėms operacijoms kurti. Apsvarstykite šį scenarijų:

def get_server_status (server_addr) # Potencialiai ilgai trunkanti operacija ... grąžinti server_status def server_ops () results = [] results.append (get_server_status ('addr1.server') results.append (get_server_status ('addr2.server') return rezultatus 

Asinchroninė to paties scenarijaus versija - neveikianti, tik tiek, kad galėtume suprasti, kaip veikia sintaksė, gali atrodyti taip.

async def get_server_status (server_addr) # Potencialiai ilgai trunkanti operacija ... grąžinti server_status async def server_ops () results = [] results.append (laukti get_server_status ('addr1.server') results.append (laukti get_server_status ('addr2). serveris ') grąžina rezultatus 

Funkcijos, pažymėtos prieš asinchroninis raktinis žodis tampa asinchroninėmis funkcijomis, taip pat žinomomis kaip korutinai. Korutinai elgiasi kitaip nei įprastos funkcijos:

  • „Coroutines“ gali naudoti kitą raktinį žodį, laukti, kuris leidžia korutinai laukti rezultatų iš kito korutino, neužblokuodamas. Kol rezultatai grįš iš laukti„Coroutine“, „Python“ laisvai persijungia tarp kitų veikiančių korutinų.
  • Korutinai gali tik būti pašaukti iš kitų asinchroninis funkcijos. Jei bėgsi server_ops () arba get_server_status () kaip yra scenarijaus tekste, negausite jų rezultatų; gausite „Python coroutine“ objektą, kurio negalima naudoti tiesiogiai.

Taigi, jei negalime paskambinti asinchroninis funkcijos iš nesinchroninių funkcijų, ir mes negalime paleisti asinchroninis funkcijos, kaip mes jas naudojame? Atsakymas: naudojant asyncio biblioteka, kuri tiltus asinchroninis ir likusius „Python“.

„Python“ asinchroninislaukti ir asyncio pavyzdys

Štai pavyzdys (vėlgi, ne funkcionalus, bet iliustratyvus), kaip galima rašyti žiniatinklio grandymo programą naudojant asinchroninis ir asyncio. Šis scenarijus užima URL sąrašą ir naudoja kelis „ asinchroninis funkcija iš išorinės bibliotekos (read_from_site_async ()), norėdami juos atsisiųsti ir apibendrinti rezultatus.

importuoti asyncio iš web_scraping_library importuoti read_from_site_async async def main (url_list): return wait wait asyncio.gather (* [read_from_site_async (_) for _ in url_list]) urls = ['//site1.com'''//othersite.com', '//newsite.com'] rezultatai = asyncio.run (pagrindinis (URL)) spausdinti (rezultatai) 

Ankstesniame pavyzdyje mes naudojame du įprastus asyncio funkcijos:

  • asyncio.run () naudojamas paleisti asinchroninis funkciją iš nesinchroninės mūsų kodo dalies, ir tokiu būdu pradėkite visą programos asinchroninę veiklą. (Taip mes bėgame pagrindinis ().)
  • asyncio.gather () imasi vienos ar daugiau asinchroniškai dekoruotų funkcijų (šiuo atveju kelios read_from_site_async () iš mūsų hipotetinės žiniatinklio grandymo bibliotekos), paleidžia juos visus ir laukia, kol bus gauti visi rezultatai.

Idėja yra tokia: tada pradedame skaitymo operaciją visose svetainėse vienu metu surinkti rezultatus jiems pasiekus (taigi asyncio.gather ()). Mes nelaukiame, kol baigsis viena operacija, kol pereisime prie kitos.

„Python“ asinchroninių programų komponentai

Jau minėjome, kaip „Python“ asinchroninėse programose korutinai naudojami kaip pagrindinis ingredientas, remdamiesi asyncio biblioteką jiems valdyti. Keli kiti elementai taip pat yra raktas į asinchronines programas „Python“:

Įvykių kilpos

asyncio biblioteka kuria ir tvarko įvykių kilpos, mechanizmai, kurie palaiko korutinas, kol jos baigiasi. „Python“ procese vienu metu turėtų būti vykdoma tik viena įvykių kilpa, kad tik programuotojui būtų lengviau sekti, kas į ją įeina.

Užduotys

Kai pateikiate korutiną į įvykių ciklą apdoroti, galite grįžti a Užduotis objektas, kuris suteikia galimybę valdyti korutino elgesį iš išorės įvykio kilpos. Pavyzdžiui, jei norite atšaukti vykdomą užduotį, galite tai padaryti paskambinę į užduotį .atšaukti () metodas.

Čia yra šiek tiek kitokia „site-scraper“ scenarijaus versija, rodanti įvykio ciklą ir užduotis darbe:

importuoti asyncio iš web_scraping_library importuoti read_from_site_async užduotis = [] async def main (url_list): for n url_list: task.append (asyncio.create_task (read_from_site_async (n))) spausdinimo užduotys) grįžti laukia asyncio.gather (* = ['//site1.com','//othersite.com','//newsite.com'] kilpa = asyncio.get_event_loop () results = loop.run_until_complete (main (URL)) spausdinti (rezultatai) 

Šis scenarijus aiškiau naudoja įvykio kilpą ir užduočių objektus.

  • .get_event_loop () metodas suteikia mums objektą, kuris leidžia mums tiesiogiai valdyti įvykių kilpą, programiškai pateikiant jai asinchronines funkcijas per .run_until_complete (). Ankstesniame scenarijuje mes galėjome paleisti tik vieną aukščiausio lygio asinchroninę funkciją naudodami asyncio.run (). Beje, .run_until_complete () daro tiksliai tai, ką sako: Vykdo visas pateiktas užduotis, kol jos bus atliktos, tada grąžins jų rezultatus į vieną paketą.
  • .create_task () metodas paima funkciją, įskaitant jos parametrus, ir grąžina mums a Užduotis objektas jį paleisti. Čia kiekvieną URL pateikiame kaip atskirą Užduotis prie įvykio ciklo ir saugokite Užduotis objektai sąraše. Atkreipkite dėmesį, kad tai galime padaryti tik įvykio ciklo viduje, tai yra viduje asinchroninis funkcija.

Kiek jums reikia kontroliuoti įvykio ciklą ir jo užduotis, priklausys nuo to, kiek sudėtinga yra jūsų sukurta programa. Jei norite tiesiog pateikti fiksuotų darbų rinkinį, kad jie būtų vykdomi vienu metu, kaip ir naudojant mūsų žiniatinklio grandiklį, jums nereikės daugybės valdymo priemonių - tik tiek, kad paleistumėte darbus ir surinktumėte rezultatus.

Priešingai, jei kuriate pilnavertę žiniatinklio struktūrą, norėsite kur kas labiau kontroliuoti korutinų ir įvykių ciklo elgesį. Pvz., Jums gali tekti grakščiai išjungti įvykio ciklą, jei programa sugenda, arba paleisti užduotis saugiai, jei renginio kilpą skambinate iš kitos gijos.

Async vs threading vs multiprocessing

Šiuo metu jums gali kilti klausimas, kodėl naudoti asinchroninį, o ne gijas ar daugiaprocesinį procesą, kurie abu jau seniai prieinami „Python“?

Pirma, yra pagrindinis skirtumas tarp asinchronizavimo ir gijų ar daugiaprocesinio apdorojimo, net jei šie dalykai įgyvendinami „Python“. „Async“ yra apie sutapimas, o apie gijas ir daugiaprocesinį procesą lygiagretumas. Lygiagretumas reiškia efektyvų laiko padalijimą tarp kelių užduočių vienu metu, pvz., Tikrinant el. Paštą laukiant registracijos maisto prekių parduotuvėje. Lygiagretumas apima kelis agentus, kurie vienas šalia kito apdoroja kelias užduotis, pvz., Maisto prekių parduotuvėje atidaryti penki atskiri registrai.

Dažniausiai „async“ yra tinkamas siūlų pakaitalas, nes „Python“ diegimas yra įdiegtas. Taip yra todėl, kad „Python“ naudoja ne OS gijas, o savo bendradarbiavimo gijas, kai vertėju visada vienu metu veikia tik viena gija. Lyginant su bendradarbiavimo temomis, „asinchroninis“ teikia keletą pagrindinių pranašumų:

  • Async funkcijos yra daug lengvesnės nei siūlai. Dešimtys tūkstančių asinchroninių operacijų, vykdomų vienu metu, turės daug mažiau pridėtinių išlaidų nei dešimtys tūkstančių gijų.
  • Async kodo struktūra leidžia lengviau apsvarstyti, kur užduotys pasirenkamos ir paliekamos. Tai reiškia, kad duomenų lenktynės ir siūlų sauga nėra tokia svarbi problema. Kadangi visos „asinchroninio įvykio“ ciklo užduotys vykdomos vienoje gijoje, „Python“ (ir kūrėjui) lengviau nuosekliai nustatyti, kaip jie pasiekia atminties objektus.
  • Async operacijas galima atšaukti ir manipuliuoti lengviau nei gijas. Užduotis objektas, iš kurio grįžtame asyncio.create_task () suteikia mums patogų būdą tai padaryti.

Kita vertus, daugiafunkcinis apdorojimas „Python“ tinkamiausias darbams, kurie yra stipriai susieti su procesoriumi, o ne su įvestimi / išvestimi. „Async“ iš tikrųjų dirba kartu su daugiaprocesiniu procesoriumi, kaip galite naudoti asyncio.run_in_executor () perduoti daug procesoriaus reikalaujančias užduotis procesų grupei iš centrinio proceso, neužblokuojant to centrinio proceso.

Kiti veiksmai naudojant „Python“ asinchronizavimą

Geriausias pirmas dalykas, kurį reikia padaryti, yra sukurti keletą paprastų savo asinchroninių programų. Gerų pavyzdžių dabar gausu, kai asinchroninis programavimas „Python“ versijose buvo atliktas keliomis versijomis ir turėjo porą metų, kad apsigyventų ir būtų plačiau naudojamas. Oficialūs dokumentai, skirti asyncio verta perskaityti, kad sužinotumėte, ką jis siūlo, net jei neplanuojate išnaudoti visų jo funkcijų.

Taip pat galite ištirti didėjantį asinchronizuotų bibliotekų ir tarpinės programinės įrangos skaičių, iš kurių daugelis teikia asinchronines, neužblokuojančias duomenų bazių jungčių, tinklo protokolų ir panašių versijas. aio-libs saugykloje yra keletas pagrindinių, tokių kaip aiohittp biblioteka prieigai prie interneto. Taip pat verta ieškoti „Python“ paketo rodyklėje bibliotekų su asinchroninis raktinis žodis. Naudojant kažką panašaus į asinchroninį programavimą, geriausias būdas išmokti yra pamatyti, kaip kiti jį pritaikė.

$config[zx-auto] not found$config[zx-overlay] not found