2015-07-08 5 views
32

PEP 0492 fügt das Schlüsselwort async zu Python 3.5 hinzu.PEP 0492 - Python 3.5 asynchrones Schlüsselwort

Wie profitiert Python von der Verwendung dieses Operators? Das Beispiel, das für eine Koroutine gegeben ist

async def read_data(db): 
    data = await db.fetch('SELECT ...') 

Nach der Dokumentation dieses

erreicht

aussetzen [ing] Ausführung von read_data Koroutine bis db.fetch awaitable abgeschlossen ist und gibt die Ergebnisdaten.

Enthält dieses Schlüsselwort async tatsächlich die Erstellung neuer Threads oder vielleicht die Verwendung eines vorhandenen reservierten asynchronen Threads?

Für den Fall, dass async einen reservierten Thread verwendet, ist es ein einzelner gemeinsamer Thread jeder in einem eigenen?

+1

Co-Routinen verwenden keine Threads. –

+3

Also, in diesem Fall, wie erreicht Python irgendeinen Vorteil aus dem Aussetzen von Ausführungen im Vergleich zu einem Generator? –

+4

Beachten Sie, dass der PEP nur bestimmte Codes leichter codieren lässt; Mit der Syntax wird keine neue Funktionalität eingeführt. Co-Routinen * kooperieren * dadurch, dass sie das Umschalten zwischen Aufgaben an vordefinierten Punkten ermöglichen (anstatt Threads, die die Ausführung zwischen verschiedenen Einheiten an beliebigen Punkten wechseln). –

Antwort

42

Nein, Co-Routinen enthalten keine Art von Threads. Co-Routinen ermöglichen kooperative Multitasking darin, dass jede Co-Routine Kontrolle freiwillig liefert. Threads andererseits wechseln zwischen Einheiten an beliebigen Punkten.

Bis zu Python 3.4 war es möglich, Co-Routinen mit Generatoren zu schreiben; Mithilfe von yield oder yield from Ausdrücken in einem Funktionskörper erstellen Sie stattdessen ein Generatorobjekt, wobei Code nur ausgeführt wird, wenn Sie über den Generator iterieren. Zusammen mit zusätzlichen Event-Loop-Bibliotheken (wie asyncio) könnten Sie Co-Routinen schreiben, die einer Event-Schleife signalisieren, dass sie beschäftigt sind (vielleicht auf I/O warten) und dass eine andere Co-Routine in der Zwischenzeit:

import asyncio 
import datetime 

@asyncio.coroutine 
def display_date(loop): 
    end_time = loop.time() + 5.0 
    while True: 
     print(datetime.datetime.now()) 
     if (loop.time() + 1.0) >= end_time: 
      break 
     yield from asyncio.sleep(1) 

Jedes Mal, wenn der oben genannte Code an die yield from asyncio.sleep(1) Linie geht, ist die Ereignisschleife frei, eine andere Co-Routine, weil diese Routine für die nächste Sekunde sowieso nichts tun geht nicht laufen.

Da Generatoren können für alle Arten von Aufgaben verwendet werden, nicht nur Co-Routinen, und weil das Schreiben eine Co-Routine Generator Syntax können Ankömmlinge verwirrend sein, stellt der PEP neue Syntax, die es klarer macht dass du eine Co-Routine schreibst.

Mit dem PEP durchgeführt, die obige Probe statt wie folgt geschrieben werden kann:

noch
async def display_date(loop): 
    end_time = loop.time() + 5.0 
    while True: 
     print(datetime.datetime.now()) 
     if (loop.time() + 1.0) >= end_time: 
      break 
     await asyncio.sleep(1) 

Das resultierende coroutine Objekt eine Ereignis-Schleife muss die Co-Routinen zu treiben; Eine Ereignisschleife würde await auf jeder Co-Routine der Reihe nach, die diejenigen Co-Routinen ausführen würde, die zur Zeit nicht abgeschlossen sind.

Die Vorteile bestehen darin, dass Sie mit nativer Unterstützung auch zusätzliche Syntax zur Unterstützung von asynchronen Kontextmanagern und Iteratoren einführen können. Das Eingeben und Verlassen eines Kontextmanagers oder das Durchlaufen eines Iterators können dann zu weiteren Punkten in Ihrer Co-Routine werden, die signalisieren, dass anderer Code ausgeführt werden kann, weil etwas wieder wartet.

+0

Gibt es eine gute Motivation, Async-Generatoren auf Basis von AsyncInterator nicht als Teil der integrierten Syntax mit Renditen zu implementieren? –

+0

Das müssen Sie auf der Python-Ideenliste diskutieren, SO-Kommentare sind dafür kein gutes Medium. –

+0

@MartijnPieters Ich habe es immer noch schwer, asyncio zu verstehen. In Ihrem Beispiel ist die Ausgabe etwas wie "2016-03-04 11: 53: 48.282701" mit einer neuen gedruckten Zeile alle 1 Sekunde. Würde das nicht bedeuten, dass Ihr Programm beim Warten aufgehört hat? Ich hatte erwartet, eine Verzögerung von 1 Sekunde beim Laufen zu sehen, und dann einen Strom von gedruckten Datumsangaben, da das 'erwarten asyncio.sleep (...)' nachgeben sollte, sobald es merkt, dass es auf "io" warten muss (in diesem Fall schlafen). IOW, die "while" -Schleife würde schnell weiterlaufen, während die '' '' '' '' '' '' '' 'endlich nachholen würden. Was verstehe ich hier falsch? – orokusaki