import asyncio # coroutine async def morceaux(message): # on appelle le code synchrone normalement print(message, "début") # avec await on rend la main await asyncio.sleep(0.5) print(message, "milieu") await asyncio.sleep(1) print(message, "fin") return f'{message} par morceaux'
Boucle d'événements
loop = asyncio.get_event_loop() loop.run_until_complete(morceaux()"run") # exécution du code: run début run milieu run fin 'run par morceau'
loop.run_until_complete( asyncio.gather( morceaux("run1"), morceaux("run2") ) ) # exécution du code : run1 début run2 début run1 milieu run2 milieu run1 fin run2 fin ['run1 par morceaux', 'run2 par morceaux']
import time async def famine(message): print(message, "début") # avec await on rend la main await asycio.sleep(0.5) print(message, "milieu") # /!\ on garde la main au lieu de la rendre time.sleep(1) print(message, "fin") return f'{message} par famine' loop.run_until_complete( asyncio.gather( morceaux("run1"), morceaux("run2") ) ) # exécution du code : run1 début run2 début run1 milieu # /!\ fonctionnement différent run1 fin run2 milieu run2 fin ['run1 par famine', 'run2 par famine']
Mais …
import time urls = ["http://www.iris.gov/pub/irs-pdf/f1040.pdf", "http://www.iris.gov/pub/irs-pdf/f1040ez.pdf", "http://www.iris.gov/pub/irs-pdf/f1040es.pdf", "http://www.iris.gov/pub/irs-pdf/f1040sb.pdf"]
import requests beg = time.time() for url in urls: req = requests.get(url) print(f"{url} returned {len(req.text)} chars") print(f"duration = {time.time() - beg}s")
Résultats:
http://www.iris.gov/pub/irs-pdf/f1040.pdf 185539 chars
http://www.iris.gov/pub/irs-pdf/f1040ez.pdf 109087 chars
http://www.iris.gov/pub/irs-pdf/f1040es.pdf 395201 chars
http://www.iris.gov/pub/irs-pdf/f1040sb.pdf 105795 chars
duration = 11.0059…
import asyncio import aiohttp async def fetch(url): async with aiohttp.ClientSession() as session: print(f"fetching {url}") async with session.get(url) as response: #print(f"{url} returned status {response.status}") raw = await response.read() print(f"{url} returned {len(raw)} bytes")
# une coroutine qui va chercher toutes les URLs # ne fait toujours rien, naturellement asyncio def fetch_urls(): await asyncio.gather(*(fetch(url) for url in urls)) loop = asyncio.get_event_loop() beg = time.time() loop.run_until_complete(fetch_urls()) print(f"duration = {time.time() - beg}s"
Résultat : fetching fttp:www.irs.gov/pub/irs-pdf/f1040sb.pdf fetching fttp:www.irs.gov/pub/irs-pdf/f1040.pdf fetching fttp:www.irs.gov/pub/irs-pdf/f1040ez.pdf fetching fttp:www.irs.gov/pub/irs-pdf/f1040es.pdf fttp:www.irs.gov/pub/irs-pdf/f1040sb.pdf returned 109984 bytes fttp:www.irs.gov/pub/irs-pdf/f1040ez.pdf returned 113498 bytes fttp:www.irs.gov/pub/irs-pdf/f1040.pdf returned 192545 bytes fttp:www.irs.gov/pub/irs-pdf/f1040es.pdf returned 409193 bytes duration = 7.2482380867004395s
import asyncio # une variante async def fetch2(url, i): async with aiohttp.ClientSession() as session: async with session.get(url) as response: #avec ici une itération asynchrone async for line in response.content: print(f'{i}', end='') return url asyncio.get_event_loop().run_until_complete( asyncio.gather(*(fetch2(url, i) for i, url in enumerate(urls)))
Résultat:
00000000000000000000000..
Autorisé
async def foo(): await bar()
Pas autorisé: SyntaxError
def foo(): await bar()
my first loop
instruction | classe d'objets | protocole | exemple |
---|---|---|---|
for | itérables | iter | liste, ensemble |
with | context managers | enter & exit | fichier |
dict[x] | hachables | hash | builtins immuables |
await | awaitables | await | objet coroutine |
await renvoie un itérateur
class Awaitables(): def __await__(self): print("in awaitable") yield "yielded" # il nous faut au moins une coroutine # pour faire await async def main() await Awaitable() # l'objet coroutine coro = main() coro.send(None)
Résultat:
in awaitable
out: yielded
# itérateur à deux coups class Awaitable2(): def __await__(self) print("step1") yeld "yeld 1" print("step2") yeld "yeld 2" return "returned"
# boilerplate async def main() return await Awaitable2()
# l'objet coroutine coro = main()
coro.send(None)
Résultat
step1
out: 'yield 1'
coro.send(None)
Résultat
step2
out: 'yield 2'
try: coro.send(None) exept Exception as e: x = e print('OOPS', type(e), e.value)
Résultat
OOPS <class 'SoptIteration'> returned
class w1: def __init__(self, marker): self.marker = marker def __await__(self): # redonner la main à la boucle yieldf"yeld {self.marker}" # retourné à await return 1
async def w2(): return await w1('first') + await w1('second') async def w3(): return await w2() + 1 async def w4(): return await w3() + 1 coro = w4()
coro.send(None) out: 'yield first'
coro.send(None) out: 'yield second'
try: coro.send(None) execept Exception as e: x = e print('OOPS', type(e), e.value) out: OOPS <class 'StopIteration' > 4
REPRENDRE LA VIDEO A 7:20