Python ist eine Stilsprache, die die asynchrone Verarbeitung implementiert, indem das Modul "asyncio" importiert und Coroutinen definiert werden. Ein ** Collout ** ist eine Struktur, mit der die Verarbeitung unterbrochen und dann fortgesetzt werden kann, im Gegensatz zum ** Unterprogramm **, bei dem es sich um eine Struktur handelt, die erst nach Abschluss der Verarbeitung angehalten wird.
Konzentrieren wir uns diesmal darauf, wie die asynchrone Verarbeitung von Python anders geschrieben ist als die von Node.js "Promise" und "async / await", mit denen ich seit einiger Zeit vertraut bin. Überlegen.
Beachten Sie, dass der Python-Quellcode weitgehend mit der offiziellen Dokumentation Coroutines and Tasks übereinstimmt.
In Python definiert die Anweisung "async def" ein Collout.
Python
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
asyncio.run(main())
Dies ist ein Beispiel für das Drucken von "Welt" eine Sekunde nach dem Drucken von "Hallo". Sie können "Warten" im Collout verwenden. Dies ist ein typisches Beispiel für eine asynchrone Verarbeitung, bei der "Asyncio.sleep (1) warten" 1 Sekunde auf die Auflösung der Verarbeitung wartet und dann die nächste Verarbeitung startet.
Was ist mit Node.js? Erstens hat Node.js keine eingebaute asynchrone Funktion wie Pythons asyncio.sleep ()
,
function sleep(sec) {
return new Promise(resolve => {
setTimeout(resolve, timeout=sec*1000);
})
}
(Im Folgenden wird die Definition dieser "Schlaf" -Funktion im Quellcode von Node.j weggelassen.) Dann können Sie wie folgt schreiben.
Node.js
async function main() {
console.log('hello');
await sleep(1);
console.log('world');
}
main();
Wenn man die beiden vergleicht, ruft Pythons kolloutierte asynchrone Verarbeitung nicht einfach den Einstiegspunkt der obersten Ebene "main ()" auf, sondern "asyncio.run (main ())" wie "asyncio". Der Unterschied besteht darin, dass Sie darauf achten müssen, dass Sie es im Argument von .run () `ausführen.
Das Anordnen des Wartens führt zur seriellen Verarbeitung.
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())
Dies ist ein Beispiel dafür, wie man 1 Sekunde wartet und dann "Hallo" druckt, dann weitere 2 Sekunden wartet und dann "Welt" druckt. In Node.js geschrieben, sollte es so aussehen:
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();
Es sieht genauso aus, ist also leicht zu verstehen.
Mit Aufgaben können Sie Collouts in Python parallel ausführen.
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())
In diesem Beispiel wird im Gegensatz zum vorherigen Beispiel die Operation "2 Sekunden warten und dann" Welt "ausgeben" gleichzeitig mit der Operation "1 Sekunde warten und dann" Hallo "ausgeben" ausgeführt, also 1 als im vorherigen Beispiel. Es wird eine Sekunde früher enden. In Python können Sie mit asyncio.create_task () ein Collout als Task umschließen und seine Ausführung planen.
In Node.js geschrieben, sollte es so aussehen:
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();
Für Node.js können Sie "Promise.all ()" verwenden.
Schauen wir uns ein anderes Beispiel an.
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())
Dies ist eine Funktion, die die Leistung berechnet, indem die Multiplikation jedes Mal um 1 Sekunde verzögert wird. Dieses Mal kam asyncio.gather ()
heraus, aber dies plant auch das Argument Collout als Task.
In Node.js geschrieben, sollte es so aussehen:
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();
In der asynchronen Python-Verarbeitung können Sie "asyncio.wait_for ()" verwenden, um es als Zeitüberschreitung zu behandeln, wenn die Verarbeitung in einer bestimmten Zeit nicht abgeschlossen ist.
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())
Im obigen Beispiel läuft beispielsweise die Funktion "Ewigkeit ()", die 3600 Sekunden lang schläft, nach 1 Sekunde ab, ohne 3600 Sekunden zu warten.
Ich glaube nicht, dass es eine präzise Möglichkeit gibt, dies in Node.js zu implementieren (soweit ich weiß).
Wenn Sie "Promise.race ()" verwenden,
await Promise.race(eternity(), timeout(1.0))
.catch(err => {
console.log('timeout!');
})
("Timeout (sec)" ist eine Funktion, die nach "sec" Sekunden "Zurückweisen" zurückgibt.) In dieser Implementierung wird das Warten auf "Ewigkeit ()" jedoch fortgesetzt, auch nachdem die Meldung "Timeout!" Nach 1 Sekunde angezeigt wird.
Siehe auch: Promise.race für Timeout-Versprechen verwenden
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.
In diesem Sinne ist es in Python sehr praktisch, Unterbrechungen in der asynchronen Verarbeitung einfach schreiben zu können.
Recommended Posts