2017-06-28 11 views
13

Ich versuche zu verstehen, wie man ein zu erwartendes Objekt macht. Die Definition aus documentation besagt:asynciously observable object - grundlegendes Beispiel

Ein Objekt mit einer __await__ -Methode, die einen Iterator zurückgibt.

von dieser Definition Guided ich den Beispielcode geschrieben:

import asyncio 

async def produce_list(): 
     num = await Customer() 
     print(num) 

class Customer(object): 

    def __await__(self): 
     return iter([1, 2, 3, 4]) 

loop = asyncio.get_event_loop() 
loop.run_until_complete(produce_list()) 

Die Strömung, die ich erwartet hatte:

  1. Ereignisschleife gibt die Kontrolle an produce_list(). produce_list() gibt die Ausführung auf num = await Customer() auf.
  2. Customer() wird ausgeführt und gibt einen Iterator zurück. Which weil gibt den ersten Wert im Iterator zurück. Q1: bin hier nicht klar, warum num nicht der Iterator selbst wird. Auch was macht ein send hier?
  3. Nach dem letzten Wert wurde der Iterator erreicht. num = 4 die Ausführung des Koroutine weiter print(num) und druckt den Wert 4.

Was ich bekommen habe:

--------------------------------------------------------------------------- 
RuntimeError        Traceback (most recent call last) 
~/workspace/dashboard/so_question_await.py in <module>() 
    16 
    17 loop = asyncio.get_event_loop() 
---> 18 loop.run_until_complete(produce_list()) 

/usr/lib/python3.5/asyncio/base_events.py in run_until_complete(self, future) 
    464    raise RuntimeError('Event loop stopped before Future completed.') 
    465 
--> 466   return future.result() 
    467 
    468  def stop(self): 

/usr/lib/python3.5/asyncio/futures.py in result(self) 
    291    self._tb_logger = None 
    292   if self._exception is not None: 
--> 293    raise self._exception 
    294   return self._result 
    295 

/usr/lib/python3.5/asyncio/tasks.py in _step(***failed resolving arguments***) 
    239     result = coro.send(None) 
    240    else: 
--> 241     result = coro.throw(exc) 
    242   except StopIteration as exc: 
    243    self.set_result(exc.value) 

~/workspace/dashboard/so_question_await.py in produce_list() 
     5 
     6 async def produce_list(): 
----> 7   num = await Customer() 
     8   print(num) 
     9 

RuntimeError: Task got bad yield: 1 

Welche Konzepte habe ich falsch hier bekommen?

Am Ende suche ich nach einem Beispiel, das Iteration durch eine Liste als ein Ereignis verwendet, um zur Steuerung der Coroutine zurückzukehren.

Antwort

4

__await__ gibt einen Iterator zurück, da der zugrunde liegende Mechanismus für Koroutinen ursprünglich auf der yield from-Syntax basiert. In der Praxis gibt __await__ entweder iter(some_future) oder some_coroutine.__await__() zurück. Es kann verwendet werden, um Objekte zu erstellen, die jedes Mal, wenn sie erwartet werden, unterschiedliche Werte erzeugen. Sehen Sie dieses einfache Beispiel:

import asyncio 
import random 

class RandomProducer: 

    def __await__(self): 
     return self.producer().__await__() 

    async def producer(self): 
     sleep = random.random() 
     value = random.randint(0, 9) 
     return await asyncio.sleep(sleep, result=value) 

async def main(): 
    producer = RandomProducer() 
    while True: 
     print(await producer) 

loop = asyncio.get_event_loop() 
loop.run_until_complete(main()) 

Ihre Kommentare zu beantworten:

Does endet jede Koroutine schließlich bis Aufruf asyncio.sleep?

Nein, und asyncio.sleep ist eigentlich nicht das Ende der Kette. Am Ende ist es immer eine Zukunft, die nachgegeben wird: Die Korotinenkette fragt die Ereignisschleife "Bitte wecke mich auf, wenn diese Zukunft ein Ergebnis hat". Im Fall von asyncio.sleep verwendet es loop.call_later, um das Ergebnis der Zukunft nach einer bestimmten Zeit festzulegen. Die Schleife stellt mehrere Verfahren für die Zeitplanung Rückrufe: loop.call_at, loop.add_reader, loop.add_writer, loop.add_signal_handler usw.

Eine asyncio Bibliothek wie aiohttp. Ich gehe davon aus, dass es irgendwo Code gibt, der nicht auf der Existenz von vorherigen Korotinen beruht.

Alle IO-Operationen müssen an die Ereignisschleife delegiert werden, um Singlethread-Parallelität zu erreichen. Zum Beispiel stützt sich aiohttp auf die loop.create_connection Coroutine zu manage the TCP connection.

+0

Ich versuche tatsächlich, ein Beispiel zu bekommen, das am Ende nicht eine vorher definierte asyncio lib Methode aufruft. Am Ende gibst du das 'have asyncio.sleep (sleep, result = value)'. Die Motivation besteht darin, zu versuchen, zu verstehen, wie man sich dem Schreiben eines neuen asyncio-Frameworks nähern würde. – TheMeaningfulEngineer

+0

Oder vielleicht um es anders zu formulieren. Hat schließlich jede Coroutine den Namen asyncio.sleep? – TheMeaningfulEngineer

+0

@TheMeaningfulEngineer 'wie würde man das Schreiben eines neuen asyncio-Frameworks angehen? Meinst du eine asyncio-Bibliothek wie [aiohttp] (http://aiohttp.readthedocs.io/en/stable/) oder eine asyncio-Alternative wie [Kuriosität] (https://github.com/dabeaz/curio)? Siehe auch meine Bearbeitung. – Vincent

Verwandte Themen