Programovanie

Začnite s asynchronizáciou v Pythone

Asynchrónne programovanie, príp async v skratke, je to vlastnosť mnohých moderných jazykov, ktorá umožňuje programu manipulovať s viacerými operáciami bez čakania alebo zavesenia na ktoromkoľvek z nich. Je to inteligentný spôsob, ako efektívne zvládnuť úlohy, ako sú sieťové alebo súborové I / O, kde sa väčšinu času programu čaká čakaním na dokončenie úlohy.

Zvážte aplikáciu na scraping webu, ktorá otvára 100 sieťových pripojení. Môžete otvoriť jedno pripojenie, počkať na výsledky, potom otvoriť ďalšie a počkať na výsledky atď. Väčšinu času, ktorý program beží, trávi čakaním na odpoveď v sieti a nie skutočnou prácou.

Async vám ponúka efektívnejšiu metódu: Otvorte všetkých 100 pripojení naraz a potom prepínajte medzi každým aktívnym pripojením, keď vrátia výsledky. Ak jedno pripojenie nevracia výsledky, prepnite na ďalšie a tak ďalej, kým všetky spojenia nevrátia svoje údaje.

Asynchronná syntax je v súčasnosti v Pythone štandardnou funkciou, ale dlhoroční Pythonisti, ktorí sú zvyknutí robiť jednu vec naraz, môžu mať problém ju obtočiť. V tomto článku sa pozrieme na to, ako asynchrónne programovanie funguje v Pythone, a na to, ako ho používať.

Upozorňujeme, že ak chcete v jazyku Python používať asynchronizáciu, je najlepšie použiť jazyk Python 3.7 alebo Python 3.8 (najnovšia verzia od tohto písania). Budeme používať asynchronnú syntax a pomocné funkcie Pythonu definované v týchto verziách jazyka.

Kedy použiť asynchrónne programovanie

Najvýhodnejšie obdobie na asynchrónne použitie je spravidla vtedy, keď sa pokúšate vykonávať prácu, ktorá má nasledujúce vlastnosti:

  • Dokončenie diela trvá dlho.
  • Oneskorenie zahŕňa čakanie na operácie I / O (disk alebo sieť), nie výpočet.
  • Táto práca zahŕňa veľa I / O operácií prebiehajúcich naraz, alebo dôjde k jednej alebo viacerým vstupno-výstupným operáciám, keď sa tiež pokúšate splniť ďalšie úlohy.

Async vám umožňuje nastaviť viac úloh súčasne a efektívne ich iterovať bez blokovania zvyšku vašej aplikácie.

Niekoľko príkladov úloh, ktoré fungujú dobre s asynchronizáciou:

  • Scraping webu, ako je popísané vyššie.
  • Sieťové služby (napr. Webový server alebo framework).
  • Programy, ktoré koordinujú výsledky z viacerých zdrojov, ktoré vrátia hodnoty dlho (napríklad simultánne databázové dotazy).

Je dôležité si uvedomiť, že asynchrónne programovanie sa líši od viacvláknového alebo viacprocesového spracovania. Asynchronné operácie prebiehajú v rovnakom vlákne, ale podľa potreby sa navzájom striedajú, vďaka čomu je asynchronizácia účinnejšia ako vytváranie vlákien alebo viac procesov pre mnoho druhov úloh. (Viac o tomto nižšie.)

Python asyncčakať a asyncio

Python nedávno pridal dve kľúčové slová, async a čakať, na vytváranie asynchrónnych operácií. Zvážte tento skript:

def get_server_status (server_addr) # Potenciálne dlhotrvajúca operácia ... návrat server_status def server_ops () results = [] results.append (get_server_status ('addr1.server') results.append (get_server_status ('addr2.server') return) výsledky 

Asynchrónna verzia toho istého skriptu - nefunkčná, dostatočná na to, aby sme získali predstavu o tom, ako funguje syntax, môže vyzerať takto.

async def get_server_status (server_addr) # Potenciálne dlhotrvajúca operácia ... vrátiť server_status async def server_ops () results = [] results.append (await get_server_status ('addr1.server') results.append (await get_server_status ('addr2. vráti výsledky 

Funkcie s predponou async kľúčové slovo sa stane asynchrónnymi funkciami, tiež známymi ako korutíny. Coroutines sa správajú odlišne od bežných funkcií:

  • Coroutines môžu použiť iné kľúčové slovo, čakať, ktorý umožňuje korutínu čakať na výsledky z iného korutínu bez blokovania. Kým sa výsledky nevrátia čakaťed coroutine, Python voľne prepína medzi ostatnými bežiacimi coroutines.
  • Korutíny môžu iba byť volaný z iných async funkcie. Ak bežíte server_ops () alebo get_server_status () tak ako je z tela scenára, nedostanete ich výsledky; dostanete korutínový objekt Pythonu, ktorý sa nedá priamo použiť.

Takže ak nemôžeme volať async funkcie z neansynchrónnych funkcií a nemôžeme ich spustiť async funkcie priamo, ako ich používame? Odpoveď: Použitím asyncio knižnica, ktorá premosťuje async a zvyšok Pythonu.

Python asyncčakať a asyncio príklad

Tu je príklad (opäť nie funkčný, ale ilustračný) toho, ako by sa dalo písať pomocou aplikácie na scraping webu async a asyncio. Tento skript obsahuje zoznam adries URL a používa viacero inštancií súboru async funkcie z externej knižnice (read_from_site_async ()), aby ste ich stiahli a zhromaždili výsledky.

import asyncio z web_scraping_library import read_from_site_async async def main (url_list): return await asyncio.gather (* [read_from_site_async (_) for _ in url_list]) urls = ['//site1.com','//othersite.com', '//newsite.com'] results = asyncio.run (main (urls)) print (results) 

Vo vyššie uvedenom príklade používame dva bežné asyncio funkcie:

  • asyncio.run () sa používa na spustenie async funkcie z neansynchrónnej časti nášho kódu, a tým odštartujú všetky asynchronné aktivity progamu. (Takto bežíme hlavný().)
  • asyncio.gather () trvá jednu alebo viac asynchrónne zdobených funkcií (v tomto prípade niekoľko prípadov read_from_site_async () z našej hypotetickej knižnice na scraping webových stránok), spustí ich všetky a čaká na všetky výsledky.

Myšlienkou je, že potom spustíme operáciu čítania pre všetky weby naraz zhromaždiť výsledky pri ich príchode (teda asyncio.gather ()). Než prejdeme na ďalšiu, nečakáme na dokončenie žiadnej operácie.

Komponenty asynchrónnych aplikácií Python

Už sme sa zmienili o tom, ako asynchrónne aplikácie v Pythone používajú ako svoju hlavnú zložku korutíny, pričom čerpajú z asyncio knižnica na ich spustenie. Pre asynchrónne aplikácie v Pythone je tiež kľúčové niekoľko ďalších prvkov:

Slučky udalostí

The asyncio knižnica vytvára a spravuje slučky udalostí, mechanizmy, ktoré prevádzkujú korutíny, kým sa nedokončia. V procese Pythonu by mala byť naraz spustená iba jedna slučka udalostí, len aby programátor ľahšie sledoval, čo doň patrí.

Úlohy

Keď zadáte korutín do slučky udalostí na spracovanie, môžete získať späť a Úloha objekt, ktorý poskytuje spôsob ovládania správania sa korutínu mimo slučky udalostí. Ak napríklad potrebujete zrušiť spustenú úlohu, môžete to urobiť tak, že zavoláte na príslušnú úlohu .Zrušiť() metóda.

Tu je trochu iná verzia skriptu škrabky webov, ktorý zobrazuje cyklus udalostí a úlohy v práci:

import asyncio z web_scraping_library import read_from_site_async tasks = [] async def main (url_list): pre n v url_list: tasks.append (asyncio.create_task (read_from_site_async (n))) tlač (úlohy) návrat čakajú asyncio.gather (* úlohy) uryn = ['//site1.com','//othersite.com','//newsite.com'] loop = asyncio.get_event_loop () results = loop.run_until_complete (main (URL)) print (výsledky) 

Tento skript explicitnejšie používa slučku udalostí a objekty úloh.

  • The .get_event_loop () metóda nám poskytuje objekt, ktorý nám umožňuje ovládať slučku udalostí priamo tým, že jej programovo odovzdáva asynchronné funkcie .run_until_complete (). V predchádzajúcom skripte sme mohli spustiť iba jednu asynchronnú funkciu najvyššej úrovne pomocou príkazu asyncio.run (). Mimochodom, .run_until_complete () robí presne to, čo hovorí: Spúšťa všetky zadané úlohy, kým nebudú hotové, a potom vráti ich výsledky v jednej dávke.
  • The .create_task () metóda vezme spustenú funkciu vrátane jej parametrov a vráti nám a Úloha objekt na jeho spustenie. Tu uvádzame každú adresu URL ako samostatnú Úloha do cyklu udalostí a Úloha objekty v zozname. Všimnite si, že to môžeme urobiť iba vo vnútri cyklu udalostí - to znamená vo vnútri async funkcia.

To, koľko kontroly nad slučkou udalostí a jej úlohami budete potrebovať, bude závisieť od toho, ako zložitá je vaša aplikácia. Ak chcete iba odoslať množinu pevných úloh, ktoré sa majú spustiť súčasne, ako je to v prípade nášho webového škrabáka, nebudete potrebovať veľa kontroly - iba toľko, aby ste mohli spúšťať úlohy a zhromažďovať výsledky.

Naopak, ak vytvárate plnohodnotný webový rámec, budete chcieť oveľa väčšiu kontrolu nad správaním sa postupov a cyklu udalostí. Možno budete musieť napríklad slušne vypnúť slučku udalostí v prípade zlyhania aplikácie alebo spustiť úlohy bezpečným spôsobom, ak voláte slučku udalostí z iného vlákna.

Asynchrón vs. vlákno vs. multiprocesor

V tejto chvíli by vás mohlo zaujímať, prečo používať namiesto vlákien alebo multiprocesingu async, ktoré sú už v Pythone dlho dostupné?

Po prvé, existuje zásadný rozdiel medzi asynchronizáciou a vláknami alebo multiprocesorom, a to aj bez ohľadu na to, ako sú tieto veci implementované v Pythone. Async je o súbežnosť, zatiaľ čo vlákna a multiprocesing sú o paralelizmus. Súbežnosť zahŕňa efektívne rozdelenie času medzi viac úloh naraz - napríklad kontrolu e-mailu počas čakania na registráciu v obchode s potravinami. Paralelizmus zahŕňa viac agentov, ktorí vedľa seba spracúvajú viac úloh - napríklad majú päť samostatných registrov otvorených v obchode s potravinami.

Async je väčšinou dobrou náhradou za vlákno, pretože vlákno je implementované v Pythone. Je to tak preto, lebo Python nepoužíva vlákna OS, ale svoje vlastné vlákna spolupráce, kde v tlmočníkovi vždy beží iba jedno vlákno. V porovnaní s kooperatívnymi vláknami poskytuje async niektoré kľúčové výhody:

  • Asynchronné funkcie sú oveľa ľahšie ako vlákna. Desiatky tisíc asynchrónnych operácií bežiacich naraz budú mať oveľa menšiu réžiu ako desaťtisíce vlákien.
  • Štruktúra asynchrónneho kódu uľahčuje uvažovanie o tom, kde sa úlohy preberajú a kde končia. To znamená, že dátové preteky a bezpečnosť vlákien nie sú menším problémom. Pretože všetky úlohy v asynchronizovanej slučke udalostí prebiehajú v jednom vlákne, je pre Python (a vývojára) jednoduchšie serializovať, ako pristupujú k objektom v pamäti.
  • Asynchronné operácie je možné zrušiť a manipulovať s nimi ľahšie ako s vláknami. The Úloha objekt, z ktorého sa vrátime asyncio.create_task () nám poskytuje praktický spôsob, ako to dosiahnuť.

Multiprocesing v Pythone je na druhej strane najlepší pre úlohy, ktoré sú viac viazané na CPU ako na I / O. Async v skutočnosti pracuje ruka v ruke s multiprocesorom, ako môžete použiť asyncio.run_in_executor () delegovať úlohy náročné na CPU do oblasti procesov z centrálneho procesu bez blokovania tohto centrálneho procesu.

Ďalšie kroky s asynchrónnym programom Python

Najlepšie urobíte, ak si vytvoríte niekoľko vlastných jednoduchých asynchronných aplikácií. Dobrých príkladov je teraz veľa, keď asynchrónne programovanie v Pythone prešlo niekoľkými verziami a trvalo pár rokov, kým sa usadili a začali sa čoraz viac používať. Oficiálna dokumentácia pre asyncio stojí za prečítanie, aby ste zistili, čo ponúka, aj keď nemáte v pláne využiť všetky jeho funkcie.

Môžete tiež preskúmať rastúci počet asynchrónnych knižníc a middleware, z ktorých mnohé poskytujú asynchrónne, neblokujúce verzie databázových konektorov, sieťových protokolov a podobne. The aio-libs repozitár má niektoré kľúčové, napríklad aiohittp knižnica pre prístup na web. Tiež stojí za to vyhľadať v knižnici Python Package Index knižnicu async kľúčové slovo. Najlepším spôsobom, ako sa naučiť niečo podobné ako asynchrónne programovanie, je zistiť, ako to ostatní používajú.

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