Programování

Začněte s asynchronizací v Pythonu

Asynchronní programování, nebo asynchronní ve zkratce, je to vlastnost mnoha moderních jazyků, která umožňuje programu manipulovat s více operacemi bez čekání nebo zavěšení na kterémkoli z nich. Je to chytrý způsob, jak efektivně zvládat úkoly, jako jsou síťové nebo souborové I / O, kde většinu času programu strávíte čekáním na dokončení úkolu.

Zvažte webovou škrabací aplikaci, která otevírá 100 síťových připojení. Můžete otevřít jedno připojení, počkat na výsledky, pak otevřít další a počkat na výsledky atd. Většinu času, kdy program běží, strávíte čekáním na síťovou odezvu, ne skutečnou prací.

Async vám dává efektivnější metodu: Otevřete všech 100 připojení najednou a poté přepínejte mezi každým aktivním připojením, jakmile vrátí výsledky. Pokud jedno připojení nevrací výsledky, přepněte na další a tak dále, dokud všechna připojení nevrátí svá data.

Asynchronní syntaxe je nyní v Pythonu standardní funkcí, ale dlouholetí Pythonisté, kteří jsou zvyklí dělat jednu věc po druhé, mohou mít problémy s tím, aby si to obtočili. V tomto článku prozkoumáme, jak asynchronní programování v Pythonu funguje, a jak jej využít.

Všimněte si, že pokud chcete použít async v Pythonu, je nejlepší použít Python 3.7 nebo Python 3.8 (nejnovější verze od tohoto psaní). Budeme používat asynchronní syntaxi a pomocné funkce Pythonu definované v těchto verzích jazyka.

Kdy použít asynchronní programování

Nejvhodnější doba pro použití async je, když se snažíte dělat práci, která má následující vlastnosti:

  • Dokončení práce trvá dlouho.
  • Zpoždění zahrnuje čekání na operace I / O (disk nebo síť), nikoli výpočet.
  • Práce zahrnuje mnoho I / O operací probíhajících najednou, nebo dochází k jedné nebo více I / O operacím, když se také snažíte splnit další úkoly.

Async vám umožní nastavit více úkolů paralelně a efektivně je iterovat, aniž byste blokovali zbytek vaší aplikace.

Některé příklady úkolů, které s asynchronizací fungují dobře:

  • Škrábání webu, jak je popsáno výše.
  • Síťové služby (např. Webový server nebo rozhraní).
  • Programy, které koordinují výsledky z více zdrojů, které vracejí hodnoty dlouho (například simultánní databázové dotazy).

Je důležité si uvědomit, že asynchronní programování se liší od multithreadingu nebo multiprocesingu. Asynchronní operace probíhají ve stejném vlákně, ale podle potřeby se navzájem poddají, takže asynchronizace je u mnoha druhů úkolů efektivnější než threading nebo multiprocesing. (Více o tom níže.)

Krajta asynchronníčekat a asyncio

Python nedávno přidal dvě klíčová slova, asynchronní a čekat, pro vytváření asynchronních operací. Zvažte tento skript:

def get_server_status (server_addr) # Potenciálně dlouhotrvající operace ... návrat server_status def server_ops () results = [] results.append (get_server_status ('addr1.server') results.append (get_server_status ('addr2.server') return) Výsledek 

Asynchronní verze stejného skriptu - nefunkční, jen pro představu o tom, jak syntaxe funguje - může vypadat takto.

async def get_server_status (server_addr) # Potenciálně dlouhotrvající operace ... vrátit server_status async def server_ops () results = [] results.append (await get_server_status ('addr1.server') results.append (await get_server_status ('addr2. vrátit výsledky) 

Funkce s předponou asynchronní klíčové slovo se stane asynchronní funkcí, známou také jako coutiny. Coroutines se chovají odlišně od běžných funkcí:

  • Coroutines mohou použít jiné klíčové slovo, čekat, což umožňuje korutinu čekat na výsledky jiného korutinu bez blokování. Dokud se výsledky nevrátí z čekated coroutine, Python volně přepíná mezi ostatními spuštěnými coutriny.
  • Coroutines může pouze být volán z jiných asynchronní funkce. Pokud běžíte server_ops () nebo get_server_status () jak je z těla skriptu, nedostanete jejich výsledky; dostanete Python coroutine objekt, který nelze použít přímo.

Pokud tedy nemůžeme zavolat asynchronní funkce z nesynchronních funkcí a nemůžeme spustit asynchronní funkce přímo, jak je používáme? Odpověď: Pomocí asyncio knihovna, která mosty asynchronní a zbytek Pythonu.

Krajta asynchronníčekat a asyncio příklad

Zde je příklad (opět nefunkční, ale ilustrativní), jak lze pomocí aplikace pro škrábání webu napsat asynchronní a asyncio. Tento skript přebírá seznam adres URL a používá více instancí souboru asynchronní funkce z externí knihovny (read_from_site_async ()) a stáhněte je a agregujte 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) 

Ve výše uvedeném příkladu používáme dva běžné asyncio funkce:

  • asyncio.run () se používá ke spuštění asynchronní funkce z neasynchronní části našeho kódu, a tak odstartuje všechny asynchronní aktivity progamu. (Takto běžíme hlavní().)
  • asyncio.gather () přebírá jednu nebo více asynchronně dekorovaných funkcí (v tomto případě několik instancí read_from_site_async () z naší hypotetické knihovny pro škrábání webů), spustí je všechny a čeká na všechny výsledky, které se dostaví.

Myšlenkou je, že poté zahájíme operaci čtení pro všechny weby najednou shromáždit výsledky, jakmile dorazí (tedy asyncio.gather ()). Než přejdeme na další, nečekáme na dokončení žádné operace.

Součásti asynchronních aplikací Pythonu

Již jsme se zmínili o tom, jak asynchronní aplikace Pythonu používají coututiny jako svoji hlavní ingredienci, přičemž čerpáme z asyncio knihovna pro jejich spuštění. Několik dalších prvků je také klíčem k asynchronním aplikacím v Pythonu:

Smyčky událostí

The asyncio knihovna vytváří a spravuje smyčky událostí, mechanismy, které spouštějí korutiny, dokud se nedokončí. V procesu Pythonu by měla běžet vždy jen jedna smyčka událostí, i když jen proto, aby programátor snáze sledoval, co do toho jde.

Úkoly

Když odešlete coroutine do smyčky události ke zpracování, můžete získat zpět a Úkol objekt, který poskytuje způsob, jak řídit chování coroutine zvenčí smyčky události. Pokud například potřebujete zrušit spuštěný úkol, můžete to provést tak, že zavoláte úkol .zrušení() metoda.

Tady je mírně odlišná verze skriptu škrabky webu, který zobrazuje smyčku událostí a úkoly v práci:

import asyncio z web_scraping_library import read_from_site_async tasks = [] async def main (url_list): for n in url_list: tasks.append (asyncio.create_task (read_from_site_async (n))) print (tasks) return await asyncio.gather (* tasks) = ['//site1.com','//othersite.com','//newsite.com'] loop = asyncio.get_event_loop () results = loop.run_until_complete (main (URL)) print (výsledky) 

Tento skript explicitněji používá smyčku událostí a objekty úloh.

  • The .get_event_loop () metoda nám poskytuje objekt, který nám umožňuje ovládat smyčku událostí přímo tím, že do ní programově odesíláme asynchronní funkce .run_until_complete (). V předchozím skriptu jsme mohli spustit pouze jednu asynchronní funkci nejvyšší úrovně pomocí asyncio.run (). Mimochodem, .run_until_complete () dělá přesně to, co říká: Spouští všechny zadané úkoly, dokud nejsou hotové, a poté vrátí jejich výsledky v jedné dávce.
  • The .create_task () metoda vezme funkci ke spuštění, včetně jejích parametrů, a vrátí nám a Úkol objekt jej spustit. Zde zadáme každou adresu URL jako samostatnou Úkol do smyčky události a uložte Úkol objekty v seznamu. Všimněte si, že to můžeme udělat pouze uvnitř smyčky událostí - to znamená uvnitř asynchronní funkce.

Kolik kontroly nad smyčkou událostí a jejími úkoly potřebujete, bude záviset na tom, jak složitá je aplikace, kterou vytváříte. Pokud chcete pouze odeslat sadu pevných úloh, které se budou spouštět souběžně, stejně jako u naší webové škrabky, nebudete potřebovat spoustu kontroly - jen tolik, abyste mohli spouštět úlohy a shromažďovat výsledky.

Naopak, pokud vytváříte plnohodnotný webový rámec, budete chtít mnohem větší kontrolu nad chováním rutin a smyčky událostí. Například budete možná muset řádně vypnout smyčku událostí v případě selhání aplikace, nebo spustit úlohy bezpečným způsobem, pokud voláte smyčku události z jiného vlákna.

Asynchronní vs. vláknové vs. multiprocesní

V tomto okamžiku vás možná zajímá, proč používat async místo vláken nebo multiprocesingu, které jsou již dlouho dostupné v Pythonu?

Nejprve je klíčový rozdíl mezi asynchronní a podprocesy nebo více procesů, a to i na rozdíl od toho, jak jsou tyto věci implementovány v Pythonu. Async je asi konkurence, zatímco vlákna a multiprocesing jsou o rovnoběžnost. Souběžnost zahrnuje efektivní rozdělení času mezi více úkolů najednou - např. Kontrola e-mailu při čekání na registraci v obchodě. Paralelismus zahrnuje více agentů, kteří vedle sebe zpracovávají více úkolů - např. Mají pět samostatných registrů otevřených v obchodě.

Async je většinou dobrou náhradou za threading, protože threading je implementován v Pythonu. Je to proto, že Python nepoužívá podprocesy OS, ale vlastní podprocesy spolupráce, kde v tlumočníkovi běží vždy jen jeden podproces. Ve srovnání s kooperativními vlákny poskytuje async některé klíčové výhody:

  • Asynchronní funkce jsou mnohem lehčí než vlákna. Desítky tisíc asynchronních operací spuštěných najednou budou mít mnohem menší režii než desítky tisíc vláken.
  • Struktura asynchronního kódu usnadňuje uvažování o tom, kde úkoly vyzvednou a odejdou. To znamená, že rasy dat a bezpečnost podprocesů jsou menší problém. Protože všechny úkoly v asynchronní smyčce událostí běží v jediném vlákně, je pro Python (a vývojáře) snazší serializovat, jak přistupují k objektům v paměti.
  • Asynchronní operace lze zrušit a manipulovat s nimi snadněji než s vlákny. The Úkol objekt, ze kterého se vrátíme asyncio.create_task () nám poskytuje praktický způsob, jak toho dosáhnout.

Multiprocesing v Pythonu je naopak nejlepší pro úlohy, které jsou silně vázány spíše na CPU než na I / O. Async ve skutečnosti funguje ruku v ruce s více procesy, jak můžete použít asyncio.run_in_executor () delegovat úlohy náročné na CPU do fondu procesů z centrálního procesu, aniž by byl blokován tento centrální proces.

Další kroky s Python async

Nejlepším řešením je vytvořit si několik jednoduchých vlastních asynchronních aplikací. Dobrých příkladů je nyní mnoho, protože asynchronní programování v Pythonu prošlo několika verzemi a trvalo několik let, než se usadilo a stalo se více používaným. Oficiální dokumentace pro asyncio stojí za přečtení, abyste zjistili, co nabízí, i když neplánujete využívat všechny jeho funkce.

Můžete také prozkoumat rostoucí počet asynchronních knihoven a middlewaru, z nichž mnohé poskytují asynchronní neblokující verze databázových konektorů, síťových protokolů a podobně. The aio-libs repozitář má některé klíčové, například aiohittp knihovna pro přístup na web. Také stojí za to prohledat knihovny balíčků Pythonu pro knihovny s asynchronní klíčové slovo. S něčím jako asynchronní programování je nejlepším způsobem, jak se to naučit, zjistit, jak to ostatní využili.

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