2015-04-06 25 views
8

Tôi cố gắng để thực hiện một ý tưởng đơn giản đi qua một dữ liệu từ thiết bị nhập chuẩn cho một coroutine:Python asyncio: đọc gọi lại và giao tiếp coroutine

import asyncio 
import sys 

event = asyncio.Event() 

def handle_stdin(): 
    data = sys.stdin.readline() 
    event.data = data # NOTE: data assigned to the event object 
    event.set() 

@asyncio.coroutine 
def tick(): 
    while 1: 
     print('Tick') 
     yield from asyncio.sleep(1) 

     if event.is_set(): 
      data = event.data # NOTE: data read from the event object 
      print('Data received: {}'.format(data)) 
      event.clear() 

def main(): 
    loop = asyncio.get_event_loop() 
    loop.add_reader(sys.stdin, handle_stdin) 
    loop.run_until_complete(tick())  

if __name__ == '__main__': 
    main() 

Mã này hoạt động tốt, tuy nhiên một phiên bản đơn giản của nó với một biến thay vì một đối tượng Event làm việc quá:

data = None 

def handle_stdin(): 
    global data 
    data = sys.stdin.readline() 

@asyncio.coroutine 
def tick(): 
    while 1: 
     print('Tick') 
     yield from asyncio.sleep(1) 

     global data 
     if data is not None: 
      print('Data received: {}'.format(data)) 
      data = None 

câu hỏi của tôi là: là cách tiếp cận với Event có đúng không? Hoặc là có một cách tốt hơn với một đối tượng asyncio để xử lý loại vấn đề? Sau đó, nếu cách tiếp cận với Event là tốt, việc sử dụng biến cũng có tốt không?

Cảm ơn bạn.

Trả lời

12

Tôi nghĩ asyncio.Queue là tốt hơn phù hợp cho các loại hình sản xuất mối quan hệ/người tiêu dùng:

import asyncio 
import sys 

queue = asyncio.Queue() 

def handle_stdin(): 
    data = sys.stdin.readline() 
    asyncio.async(queue.put(data)) # Queue.put is a coroutine, so you can't call it directly. 

@asyncio.coroutine 
def tick(): 
    while 1: 
     data = yield from queue.get() 
     print('Data received: {}'.format(data)) 

def main(): 
    loop = asyncio.get_event_loop() 
    loop.add_reader(sys.stdin, handle_stdin) 
    loop.run_until_complete(tick())  

if __name__ == '__main__': 
    main() 

Có ít logic tham gia hơn so với một Event, mà bạn cần phải chắc chắn rằng bạn thiết lập/unset đúng và không cần phải có sleep, đánh thức, kiểm tra, quay lại chế độ ngủ, vòng lặp, như với biến toàn cầu. Vì vậy, cách tiếp cận Queue đơn giản hơn, nhỏ hơn và chặn vòng lặp sự kiện ít hơn các giải pháp có thể khác của bạn. Các giải pháp khác về mặt kỹ thuật là chính xác, ở chỗ chúng sẽ hoạt động đúng cách (miễn là bạn không giới thiệu bất kỳ lệnh gọi yield from nào bên trong nếu các khối if event.is_set()if data is not None:). Họ chỉ là một chút clunky.

+0

Cảm ơn bạn rất nhiều @ dano, 'xếp hàng' phương pháp tiếp cận trông thực sự tốt hơn so với' 'sự kiện' 'một. –

2

Nếu bạn muốn đợi một sự kiện, có thể bạn đang sử dụng Event.wait thay vì bỏ phiếu is_set.

@asyncio.coroutine 
def tick(): 
    while True: 
     yield from event.wait() 
     print('Data received: {}'.format(event.data)) 
     event.clear() 
+0

Đúng, trên thực tế, ngay cả một 'đơn giản từ event.wait()' mà không có một vòng lặp nên là đủ. –

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