Een async begroeting
Maak ready_label(name) een async functie die de tekst "<naam>: klaar" teruggeeft. De meegegeven naam blijft exact behouden.
Een reserveringssysteem wacht vaak op informatie voordat het verder kan. Tijdens dat wachten hoeft het programma niet voortdurend dezelfde vraag te stellen. Python kan de uitvoering op een afgesproken punt onderbreken en later verdergaan, met de lokale variabelen nog intact.
Een coroutinefunctie begint met async def. Zij lijkt op een gewone functie: ze heeft parameters, lokale variabelen en een mogelijke return. Het verschil zit in wat er bij het aanroepen gebeurt.
De aanroep greet("Romy") voert de functiebody nog niet uit. Hij maakt een coroutineobject: een beschrijving van een uitvoering die nog moet plaatsvinden. Dat object is dus nog geen begroeting en ook geen taak die vanzelf op de achtergrond werkt.
Met await laat je vanuit een coroutine het beschreven werk uitvoeren en wacht je op het resultaat. Een return in de aangeroepen coroutine wordt de waarde van de await-expressie. Je kunt die waarde daarna opslaan, afdrukken of verder berekenen.
Een eventloop regelt welk werk verder kan wanneer iets waarop het wacht beschikbaar is. In een gewoon Python-script gebruik je asyncio.run(main()) om de bovenste coroutine uit te voeren en haar resultaat terug te krijgen. Binnen main gebruik je vervolgens await voor andere coroutines.
import asyncio
async def greet(name):
print("Begonnen")
await asyncio.sleep(0)
return f"Welkom, {name}"
async def main():
print(await greet("Romy"))
asyncio.run(main())Begonnen Welkom, Romy
Het voorbeeld wacht met asyncio.sleep(0). Dat is hier een oefenpauze waarmee een coroutine gelegenheid geeft om ander gepland werk te laten lopen. Het is geen meting van tijdwinst en maakt een berekening niet vanzelf sneller.
De begroeting verschijnt pas nadat haar coroutine is uitgevoerd. De bovenste main-functie geeft haar resultaat door aan print. De gewone regel onderaan vormt de ingang van het script; verspreid geen extra asyncio.run-aanroepen door de async functies zelf.
Een lijst is geen lijstiterator en een coroutineobject is geen uitgerekende waarde. Het helpt om die verschillen ook in je variabelenamen zichtbaar te maken: bijvoorbeeld pending voor het object en answer voor het uiteindelijke antwoord. Bewaar het object alleen wanneer je het later ook werkelijk gaat uitvoeren.
import asyncio
import inspect
events = []
async def read_number():
events.append("gelezen")
await asyncio.sleep(0)
return 12
pending = read_number()
print(inspect.iscoroutine(pending))
print(events)
print(asyncio.run(pending))
print(events)True [] 12 ['gelezen']
Vóór asyncio.run is de gebeurtenissenlijst leeg. Daarna zie je dat de body heeft gelopen en dat het resultaat beschikbaar is. Hetzelfde coroutineobject kun je niet opnieuw afwachten alsof het een herbruikbare functie is; voor een volgende uitvoering roep je de coroutinefunctie opnieuw aan.
Wie answer = read_value() schrijft, krijgt bij een async leesfunctie een coroutineobject. Daarmee kun je nog geen verdubbeling uitrekenen. answer = await read_value() levert de echte gelezen waarde op.
Laat je een coroutineobject ongebruikt liggen, dan kan Python bovendien waarschuwen dat de coroutine nooit is afgewacht. Alleen een functie async noemen helpt dus niet: iedere benodigde async stap moet ook in de uitvoeringsketen terechtkomen. Een fout uit een afgewachte coroutine gaat op het await-punt door naar de aanroeper.
In deze les volgen de bewerkingen elkaar bewust op. Bij left = await first() en daarna right = await second() begint de tweede pas wanneer de eerste klaar is. Twee await-expressies naast elkaar leveren daardoor nog geen gelijktijdige taken op.
De oefenfuncties ontvangen tekst, gehele getallen of meegegeven async leesfuncties. Lees zo'n meegegeven functie precies eenmaal en gebruik haar werkelijke resultaat. In de laatste opdracht geef je de twee resultaten als lijst terug, in dezelfde volgorde als de leesfuncties.
Maak ready_label(name) een async functie die de tekst "<naam>: klaar" teruggeeft. De meegegeven naam blijft exact behouden.
Geef vanuit async add_later(left, right) de som van de twee gehele getallen terug. Gebruik de werkelijke argumenten, ook bij nul en negatieve waarden.
Wacht in async double_read(read_value) precies eenmaal op de meegegeven async functie zonder argumenten. Geef tweemaal haar gehele resultaat terug. Als de lezer faalt, geef je datzelfde exceptionobject door.
Wacht in async read_in_order(first, second) eerst op first() en daarna op second(). Roep elke functie eenmaal aan en geef de twee waarden als lijst in die volgorde terug. Geef een fout uit een stap ongewijzigd door; na een fout van first start second niet.
async def maakt een coroutinefunctie; aanroepen levert eerst een coroutineobject.await voert benodigd async werk uit en levert de geretourneerde waarde.asyncio.run(main()); twee opeenvolgende awaits blijven opeenvolgend.Hierna maak je met echte taken zichtbaar hoe onafhankelijke bewerkingen kunnen overlappen.
Voer je code uit en ontdek
wat je hebt gemaakt.
Je hoeft het niet in één keer goed te doen. Na het uitvoeren zie je hier welke stappen al kloppen.