J'ai lu de nombreux exemples, billets de blog, questions/réponses concernant asyncio
async
/await
EN PYTHON 3.5+, BEAUCOUP ÉTAIENT COMPLEXES, LE PLUS SIMPLE QUE J'AI TROUVÉ ÉTAIT PROBABLEMENT CELUI-CI . NÉANMOINS, IL UTILISE ensure_future
ET, POUR L’APPRENTISSAGE DE LA PROGRAMMATION ASYNCHRONE EN PYTHON, JE VOUDRAIS VOIR SI UN EXEMPLE ENCORE PLUS MINIMAL EST POSSIBLE (C’EST-À-DIRE QUELS SONT LES OUTILS MINIMUM NÉCESSAIRES POUR FAIRE UN EXEMPLE DE BASE ASYNC/WAIT ).
QUESTION: À DES FINS D'APPRENTISSAGE SUR LA PROGRAMMATION ASYNCHRONE EN PYTHON, EST-IL POSSIBLE DE DONNER UN EXEMPLE SIMPLE/_ MONTRANT COMMENT FONCTIONNE async
/await
, en n'utilisant que ces deux mots clés + asyncio.get_event_loop()
+ run_until_complete
+, mais aucune autre fonction asyncio
?
Exemple: quelque chose comme ceci:
import asyncio
async def async_foo():
print("async_foo started")
await asyncio.sleep(5)
print("async_foo done")
async def main():
asyncio.ensure_future(async_foo()) # fire and forget async_foo()
print('Do some actions 1')
await asyncio.sleep(5)
print('Do some actions 2')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
mais sans ensure_future
, et montre toujours comment wait/async fonctionne.
est-il possible de donner un exemple simple montrant comment
async
await
fonctionne en utilisant uniquement ces deux mots clés +asyncio.get_event_loop()
+run_until_complete
+ autre code Python mais pas d'autres fonctionsasyncio
?
De cette façon, il est possible d'écrire du code qui fonctionne:
import asyncio
async def main():
print('done!')
if __== '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
_/Mais de cette façon, il est impossible de démontrer pourquoi vous avez besoin d'asyncio.
À propos, pourquoi avez-vous besoin de asyncio
, pas seulement du code brut? Answer is - asyncio
vous permet d’obtenir des avantages en termes de performances lorsque vous parallélisez des opérations de blocage d’E/S (telles que la lecture/l’écriture sur le réseau). Et pour écrire des exemples utiles, vous devez utiliser une implémentation asynchrone de ces opérations.
Veuillez lire cette réponse pour une explication plus détaillée.
Upd:
ok, voici un exemple qui utilise asyncio.sleep
pour imiter l'opération de blocage d'E/S et asyncio.gather
qui montre comment vous pouvez exécuter plusieurs opérations de blocage simultanément:
import asyncio
async def io_related(name):
print(f'{name} started')
await asyncio.sleep(1)
print(f'{name} finished')
async def main():
await asyncio.gather(
io_related('first'),
io_related('second'),
) # 1s + 1s = over 1s
if __== '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Sortie:
first started
second started
first finished
second finished
[Finished in 1.2s]
Notez comment les deux io_related
ont alors commencé, après une seconde à la fois.
Pour répondre à vos questions, je proposerai 3 solutions différentes au même problème.
cas 1: juste un python normal
import time
def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
def sum(name, numbers):
total = 0
for number in numbers:
print(f'Task {name}: Computing {total}+{number}')
sleep()
total += number
print(f'Task {name}: Sum = {total}\n')
start = time.time()
tasks = [
sum("A", [1, 2]),
sum("B", [1, 2, 3]),
]
end = time.time()
print(f'Time: {end-start:.2f} sec')
sortie:
Task A: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task A: Sum = 3
Task B: Computing 0+1
Time: 2.01
Task B: Computing 1+2
Time: 3.01
Task B: Computing 3+3
Time: 4.01
Task B: Sum = 6
Time: 5.02 sec
cas 2: async/attend mal fait
import asyncio
import time
async def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
async def sum(name, numbers):
total = 0
for number in numbers:
print(f'Task {name}: Computing {total}+{number}')
await sleep()
total += number
print(f'Task {name}: Sum = {total}\n')
start = time.time()
loop = asyncio.get_event_loop()
tasks = [
loop.create_task(sum("A", [1, 2])),
loop.create_task(sum("B", [1, 2, 3])),
]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
end = time.time()
print(f'Time: {end-start:.2f} sec')
sortie:
Task A: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task A: Sum = 3
Task B: Computing 0+1
Time: 2.01
Task B: Computing 1+2
Time: 3.01
Task B: Computing 3+3
Time: 4.01
Task B: Sum = 6
Time: 5.01 sec
cas 3: async/wait done right (identique au cas 2 sauf la fonction sleep
)
import asyncio
import time
async def sleep():
print(f'Time: {time.time() - start:.2f}')
await asyncio.sleep(1)
async def sum(name, numbers):
total = 0
for number in numbers:
print(f'Task {name}: Computing {total}+{number}')
await sleep()
total += number
print(f'Task {name}: Sum = {total}\n')
start = time.time()
loop = asyncio.get_event_loop()
tasks = [
loop.create_task(sum("A", [1, 2])),
loop.create_task(sum("B", [1, 2, 3])),
]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
end = time.time()
print(f'Time: {end-start:.2f} sec')
sortie:
Task A: Computing 0+1
Time: 0.00
Task B: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task B: Computing 1+2
Time: 1.00
Task A: Sum = 3
Task B: Computing 3+3
Time: 2.00
Task B: Sum = 6
Time: 3.01 sec
case 1
avec case 2
donne le même 5 seconds
, alors que case 3
ne contient que 3 seconds
. Donc, le async/await done right
est plus rapide.
La raison de la différence est dans l'implémentation de la fonction sleep
.
# case 1
def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
# case 2
async def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
# case 3
async def sleep():
print(f'Time: {time.time() - start:.2f}')
await asyncio.sleep(1)
La fonction sleep
dans case 1
et case 2
sont les mêmes. Ils "dorment" sans permettre à d'autres d'utiliser les ressources . Tandis que case 3
permet d'accéder aux ressources lorsqu'il est endormi.
Dans case 2
, nous avons ajouté async
à la fonction normale. Cependant, la boucle d’événement l’exécutera sans interruption. Pourquoi? Parce que nous n'avons pas indiqué où la boucle est autorisée à interrompre votre fonction pour exécuter une autre tâche.
Dans case 3
, nous avons indiqué à la boucle d'événements exactement où interrompre la fonction pour exécuter une autre tâche. Où exactement?
# case 3
async def sleep():
print(f'Time: {time.time() - start:.2f}')
await asyncio.sleep(1) # <-- Right here!
Plus sur ceci lire ici