2017-06-28 23 views
13

Tôi đang cố gắng để hiểu làm thế nào để làm cho một đối tượng awaitable. Định nghĩa từ các trạng thái documentation:asyncio awaitable object - ví dụ cơ bản

Một đối tượng có phương thức __await__ trả về trình lặp.

Được hướng dẫn bởi định nghĩa mà tôi đã viết đoạn code mẫu:

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()) 

Dòng mà tôi mong đợi là:

  1. loop tổ chức sự kiện cung cấp cho kiểm soát để produce_list(). produce_list() từ bỏ thực thi trên num = await Customer().
  2. Customer() được thực hiện và trả về một trình lặp. Mà vì trả về giá trị đầu tiên trong trình lặp. Q1: không rõ ràng tại sao num không trở thành bản thân trình lặp. Ngoài ra những gì đang làm một send ở đây?
  3. Khi đã đạt đến giá trị cuối cùng của trình lặp. num = 4 thực hiện các coroutine tiếp tục print(num), và in giá trị 4.

gì tôi nhận:

--------------------------------------------------------------------------- 
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 

tôi đã nhận được gì khái niệm sai ở đây?

Cuối cùng, tôi đang tìm một ví dụ sử dụng phép lặp qua danh sách dưới dạng sự kiện để trở về sự kiểm soát của coroutine.

Trả lời

4

__await__ trả về trình lặp bởi vì cơ chế cơ bản cho coroutines ban đầu dựa trên cú pháp yield from. Trong thực tế, __await__ trả lại iter(some_future) hoặc some_coroutine.__await__(). Nó có thể được sử dụng để tạo ra các đối tượng tạo ra các giá trị khác nhau mỗi khi chúng được chờ đợi. Xem ví dụ này đơn giản:

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()) 

Để trả lời bình luận của bạn:

Liệu mỗi coroutine cuối cùng kết thúc lên gọi asyncio.sleep?

Không, và asyncio.sleep thực ra không phải là kết thúc của chuỗi. Ở dưới cùng, nó luôn luôn là một tương lai đang được mang lại: chuỗi coroutine hỏi vòng lặp sự kiện "hãy đánh thức tôi dậy khi tương lai này có kết quả". Trong trường hợp của asyncio.sleep, nó sử dụng loop.call_later để đặt kết quả của tương lai sau một khoảng thời gian nhất định. Vòng cung cấp phương pháp hơn cho callbacks lịch: loop.call_at, loop.add_reader, loop.add_writer, loop.add_signal_handler vv

Một thư viện asyncio như aiohttp. Tôi giả sử có một số mã ở đâu đó mà không phụ thuộc vào sự tồn tại của các coroutines trước đó.

Tất cả các hoạt động IO phải kết thúc ủy quyền cho vòng lặp sự kiện để đạt được đồng thời một luồng. Ví dụ: aiohttp dựa trên loop.create_connection coroutine để manage the TCP connection.

+0

Tôi thực sự đang cố gắng lấy ví dụ rằng cuối cùng không gọi phương thức asyncio lib đã được xác định trước đó. Cuối cùng, bạn đang truyền "await asyncio.sleep" (sleep, result = value) '. Động lực là cố gắng hiểu làm thế nào người ta tiếp cận việc viết một khung công tác asyncio mới. – TheMeaningfulEngineer

+0

Hoặc có thể nói lại nó. Có phải tất cả các coroutine cuối cùng kết thúc lên gọi là 'asyncio.sleep'? – TheMeaningfulEngineer

+0

@TheMeaningfulEngineer 'cách tiếp cận cách viết một khung công tác asyncio mới.' Bạn có nghĩa là một thư viện asyncio như [aiohttp] (http://aiohttp.readthedocs.io/en/stable/) hoặc một giải pháp thay thế asyncio chẳng hạn như [curio] (https://github.com/dabeaz/curio)? Ngoài ra, hãy xem chỉnh sửa của tôi. – Vincent

Các vấn đề liên quan