Ich bekomme den Fluss von asyncio
in Python 3.5, aber ich habe keine Beschreibung der Dinge, die ich sein sollte und Dinge, die ich nicht sein sollte oder wo es vernachlässigbar wäre. Muss ich nur mein bestes Urteil in Bezug auf "Dies ist eine IO-Operation und sollte daher await
ED" sein?Wann zu verwenden und wann nicht Python 3.5 `erwarten 'verwenden?
Antwort
Standardmäßig ist Ihr gesamter Code synchron. Sie können asynchrone definierende Funktionen mit async def
machen und diese Funktionen mit await
aufrufen. Korrektere Frage ist "Wann sollte ich asynchronen Code anstelle von synchron schreiben?". Die Antwort lautet: "Wenn Sie davon profitieren können". In den meisten Fällen, wie Sie bemerkt, Sie Vorteil bekommen, wenn Sie mit I/O-Operationen arbeiten:
# Synchronous way:
download(url1) # takes 5 sec.
download(url2) # takes 5 sec.
# Total time: 10 sec.
# Asynchronous way:
await asyncio.gather(
download(url1), # takes 5 sec.
download(url2) # takes 5 sec.
)
# Total time: only 5 sec. (+ little overhead for using asyncio)
Natürlich, wenn Sie Funktion erstellt, den asynchronen Code verwendet, sollte diese Funktion auch asynchron sein (sollte so definiert werden, async def
). Aber jede asynchrone Funktion kann frei synchronen Code verwenden. Es macht keinen Sinn, ohne irgendeinen Grund asynchron synchron Code zu werfen:
# extract_links(url) should be async because it uses async func download() inside
async def extract_links(url):
# download() was created async to get benefit of I/O
data = await download(url)
# parse() doesn't work with I/O, no sense to make it async
links = parse(data)
return links
Eine sehr wichtige Sache ist, dass jeder langSynchronLauf (> 50 ms, zum Beispiel, ist es schwer, genau zu sagen) wird all Ihre asynchronen einfrieren Operationen für diese Zeit:
async def extract_links(url):
data = await download(url)
links = parse(data)
# if search_in_very_big_file() takes much time to process,
# all your running async funcs (somewhere else in code) will be friezed
# you need to avoid this situation
links_found = search_in_very_big_file(links)
Sie können es vermeiden Aufruf lange synchrone Funktionen in separaten Prozess ausgeführt wird (und warten auf Ergebnis):
executor = ProcessPoolExecutor(2)
async def extract_links(url):
data = await download(url)
links = parse(data)
# Now your main process can handle another async functions while separate process running
links_found = await loop.run_in_executor(executor, search_in_very_big_file, links)
Ein weiteres Beispiel: Wenn Sie requests
in asyncio verwenden müssen. requests.get
ist nur synchrone Long-Running-Funktion, die Sie nicht innerhalb Async-Code aufrufen sollten (wieder, um Einfrieren zu vermeiden). Aber es läuft wegen I/O lange, nicht wegen langer Berechnungen. In diesem Fall können Sie ThreadPoolExecutor
statt ProcessPoolExecutor
verwenden, um einige Multiprozessing Overhead zu vermeiden:
executor = ThreadPoolExecutor(2)
async def download(url):
response = await loop.run_in_executor(executor, requests.get, url)
return response.text
Entschuldigung für die verspätete Antwort bestätigen. Danke für die Erklärung, die mir sehr geholfen hat! – dalanmiller
Sie haben noch viel Freiheit. Wenn Sie eine Funktion aufrufen müssen, müssen Sie herausfinden, ob dies eine normale Funktion oder eine Routine ist. Sie müssen das Schlüsselwort await
genau dann verwenden, wenn die von Ihnen aufgerufene Funktion eine Coroutine ist.
Wenn async
Funktionen beteiligt sind, sollte es eine "Ereignisschleife" geben, die diese async
Funktionen orchestriert. Streng genommen ist es nicht notwendig, Sie können "manuell" die async
Methode ausführen, die Werte an sie sendet, aber wahrscheinlich möchten Sie es nicht tun. Die Ereignisschleife verfolgt die noch nicht abgeschlossenen Koroutinen und wählt die nächste aus, um weiter zu laufen. asyncio
Modul bietet eine Implementierung von Ereignisschleife, aber dies ist nicht die einzige mögliche Implementierung.
Betrachten Sie diese zwei Zeilen Code:
x = get_x()
do_something_else()
und
x = await aget_x()
do_something_else()
Semantic ist absolut das gleiche: eine Methode aufrufen, die einen Wert erzeugt, wenn der Wert, den es Variable bereit zuweisen ist x
und etwas anderes machen. In beiden Fällen wird die do_something_else
-Funktion erst aufgerufen, nachdem die vorherige Codezeile beendet wurde.Es bedeutet nicht einmal, dass vor oder nach oder während der Ausführung der asynchronen aget_x
Methode die Kontrolle der Ereignisschleife übergeben wird.
Dennoch gibt es einige Unterschiede:
- den zweiten Schnipsel nur in einer anderen
async
Funktion aget_x
Funktion nicht gewohnt angezeigt werden kann, aber Koroutine (das entweder mitasync
Schlüsselwort oder dekoriert als Koroutine deklariert)aget_x
ist in der Lage zu "kommunizieren" mit der Ereignisschleife: das sind einige Objekte dazu. Die Ereignisschleife sollte in der Lage sein, diese Objekte als Anforderungen zu interpretieren, um einige Operationen auszuführen (z. B. um eine Netzwerkanforderung zu senden und auf eine Antwort zu warten, oder einfach diese Coroutine fürn
Sekunden anzuhalten). Üblicheget_x
Funktion ist nicht in der Lage, mit Ereignisschleife zu kommunizieren.
- 1. Wann socket.io zu verwenden und wann Ajax zu verwenden
- 2. Wann node.js verwenden und wann Ajax verwenden?
- 3. Wann System() verwenden und wann execv *() verwenden?
- 4. Wann und wann nicht CoreAnimation verwenden
- 5. Wann Datenbankansichten verwenden und wann nicht?
- 6. Wann GWT zu verwenden ist und wann nicht
- 7. Wann NICHT NoSQL zu verwenden?
- 8. Wann NSURLProtocol zu verwenden?
- 9. Wann sollte ich async verwenden/abwarten und wann nicht?
- 10. Luftstrom: Wann SellerieExecutor und wann MesosExecutor verwenden
- 11. Railties - Wann zu verwenden
- 12. Wann selbst zu verwenden?
- 13. Wann Texturansichten zu verwenden
- 14. Wann nicht ACS verwenden?
- 15. Wann zu verwenden behalten und wann zu kopieren
- 16. Wann "if" und "wann" in Clojure verwenden?
- 17. Wann verwenden wir POJO und wann verwenden wir SLSB
- 18. Wann ein Modul zu verwenden, und wann eine Klasse
- 19. Wann 'if ... else if' und wann zu verwenden ist
- 20. Wann CheckBox zu verwenden ist und wann Switch
- 21. Java: Wann Generika-Methode zu verwenden und wann explizite Methode
- 22. Wann zu verwenden und wann importieren in Aurelia?
- 23. Wann lohnt es sich, `data.table` zu verwenden? Wann kann ich die größten Leistungssteigerungen erwarten?
- 24. Wann HTML5 in Android zu verwenden? Wann nicht benutzen?
- 25. Wann sollten wir instanceof verwenden und wann nicht
- 26. Wann DropWizard Bundles zu verwenden?
- 27. GWT: Wann LazyDomElement zu verwenden?
- 28. CompositeWPF: EventAggregator - wann zu verwenden?
- 29. Wann ist Q_NULLPTR zu verwenden?
- 30. JPA - wann Beziehungen zu verwenden?
Lesen Sie [PEP 492] (https://www.python.org/dev/peps/pep-0492/#id50) für Details, aber im Allgemeinen sollten Sie 'erwarten' auf allen Futures, '@coroutine 'dekorierte Funktionen &' async def' Funktionen. –