Python est un langage de style qui implémente un traitement asynchrone en important le module ʻasyncio` et en définissant des coroutines. Un ** collout ** est une structure qui permet d'interrompre puis de reprendre le traitement, contrairement au ** sous-programme **, qui est une structure qui ne s'arrête pas tant que le traitement n'est pas terminé.
Cette fois, concentrons-nous sur la manière dont le traitement asynchrone de Python est écrit différemment de «Promise» et «async / await» de Node.js, que je connais depuis longtemps. pense.
Notez que le code source Python est largement conforme à la documentation officielle Coroutines and Tasks.
En Python, l'instruction ʻasync def` définit un collout.
Python
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
asyncio.run(main())
Ceci est un exemple d'impression de "monde" une seconde après l'impression de "bonjour".
Vous pouvez utiliser ʻawaitdans le collout. Ceci est un exemple typique de traitement asynchrone, où ʻawait asyncio.sleep (1)
attend la résolution du traitement pendant 1 seconde puis démarre le traitement suivant.
Qu'en est-il de Node.js? Premièrement, Node.js n'a pas de fonction asynchrone intégrée comme ʻasyncio.sleep () `de Python,
function sleep(sec) {
return new Promise(resolve => {
setTimeout(resolve, timeout=sec*1000);
})
}
(Ci-après, la définition de cette fonction «sleep» est omise dans le code source de Node.js). Ensuite, vous pouvez écrire comme suit.
Node.js
async function main() {
console.log('hello');
await sleep(1);
console.log('world');
}
main();
En comparant les deux, le traitement asynchrone collouté de Python n'appelle pas simplement le point d'entrée de niveau supérieur main ()
, mais ʻasyncio.run (main ()) , ʻasyncio. La différence est que vous devez faire attention à l'exécuter dans l'argument de .run ()
.
L'organisation de l'attente entraînera un traitement en série.
Python
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
Ceci est un exemple d'attente pendant 1 seconde, puis d'impression de «bonjour», puis d'attente de 2 secondes supplémentaires, puis d'impression de «monde». Écrit dans Node.js, cela devrait ressembler à ceci:
Node.js
async function say_after(delay, what) {
await sleep(delay);
console.log(what);
}
async function main() {
console.log(`started at ${new Date().toTimeString()}`);
await say_after(1, 'hello');
await say_after(2, 'world');
console.log(`finished at ${new Date().toTimeString()}`);
}
main();
Cela ressemble au même, donc c'est facile à comprendre.
Les tâches vous permettent d'exécuter des collouts en parallèle en Python.
Python
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
task1 = asyncio.create_task(
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(2, 'world'))
print(f"started at {time.strftime('%X')}")
await task1
await task2
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
Dans cet exemple, contrairement à l'exemple précédent, l'opération "attendre 2 secondes puis sortir" monde "" est effectuée en même temps que l'opération "attendre 1 seconde puis sortir" bonjour "", donc 1 que l'exemple précédent. Cela se terminera une seconde plus tôt. En Python, ʻasyncio.create_task () `vous permet d'envelopper un collout en tant que tâche et de planifier son exécution.
Écrit dans Node.js, cela devrait ressembler à ceci:
Node.js
async function say_after(delay, what) {
await sleep(delay);
console.log(what);
}
async function main() {
const task1 = say_after(1, 'hello');
const task2 = say_after(2, 'world');
console.log(`started at ${new Date().toTimeString()}`);
await Promise.all([task1, task2]);
console.log(`finished at ${new Date().toTimeString()}`);
}
main();
Pour Node.js, vous pouvez utiliser Promise.all ()
.
Regardons un autre exemple.
Python
import asyncio
async def factorial(name, number):
f = 1
for i in range(2, number + 1):
print(f"Task {name}: Compute factorial({i})...")
await asyncio.sleep(1)
f *= i
print(f"Task {name}: factorial({number}) = {f}")
async def main():
await asyncio.gather(
factorial("A", 2),
factorial("B", 3),
factorial("C", 4),
)
asyncio.run(main())
Il s'agit d'une fonction qui calcule la puissance en retardant la multiplication de 1 seconde à chaque fois. Cette fois, ʻasyncio.gather () `est sorti, qui planifie également l'argument coroutine comme une tâche.
Écrit dans Node.js, cela devrait ressembler à ceci:
Node.js
async function factorial(name, number) {
let f = 1;
for (let i=2;i<=number;++i) {
console.log(`Task ${name}: Compute factorial(${i})...`);
await sleep(1);
f *= i;
}
console.log(`Task ${name}: factorial(${number}) = ${f}`);
}
async function main() {
await Promise.all([
factorial("A", 2),
factorial("B", 3),
factorial("C", 4)
]);
}
main();
Dans le traitement asynchrone Python, vous pouvez utiliser ʻasyncio.wait_for () `pour le traiter comme un timeout si le traitement n'est pas terminé dans un certain laps de temps.
Python
import asyncio
async def eternity():
await asyncio.sleep(3600)
print('yay!')
async def main():
try:
await asyncio.wait_for(eternity(), timeout=1.0)
except asyncio.TimeoutError:
print('timeout!')
asyncio.run(main())
Par exemple, dans l'exemple ci-dessus, la fonction ʻeternity () `qui dort pendant 3600 secondes expire en fait après 1 seconde sans attendre 3600 secondes.
Je ne pense pas qu'il existe un moyen concis d'implémenter cela dans Node.js (pour autant que je sache).
Certainement, si vous utilisez Promise.race ()
,
await Promise.race(eternity(), timeout(1.0))
.catch(err => {
console.log('timeout!');
})
(Timeout (sec)
est une fonction qui renvoie rejeter
après sec
secondes).
Cependant, dans cette implémentation, même après 1 seconde, "timeout!" S'affiche, ʻeternity () `continue d'attendre.
Voir aussi: Use Promise.race to Timeout Promises
Caveat: Cleanup The timeout does not cause the other promise to clean up or cancel. For example, if a database-write promise were to be Promise.race ‘d against a timeout, and if the timeout completed first, then the database write operation would still be running and may (eventually) succeed, but the rest of your application will think it failed. Make sure to introduce logic to cancel the operation in case your application initiates a timeout. Handling cleanup and canceling logic is a tricky subject, as the feature is not built into JavaScript.
Dans cet esprit, il est assez pratique en Python de pouvoir simplement écrire des interruptions dans le traitement asynchrone.
Recommended Posts