2017-06-11 30 views
1

我想圍繞python asyncio包裹我的頭。關於asyncio的驗證

from datetime import datetime 
import asyncio 


def print_time(number, loop): 
    et = loop.time() + 10.0 
    while True: 
     print('loop {} time {}'.format(number, datetime.now())) 
     if (loop.time() >= et): 
      break 
     yield from asyncio.sleep(3) 


loop = asyncio.get_event_loop() 

asyncio.ensure_future(print_time(1,loop)) 
asyncio.ensure_future(print_time(2,loop)) 

loop.run_forever() 

的輸出(來自Jupyter筆記本)

loop 1 time 2017-06-11 21:38:47.398280 
loop 2 time 2017-06-11 21:38:47.398452 
loop 1 time 2017-06-11 21:38:50.401818 
loop 2 time 2017-06-11 21:38:50.402335 
loop 1 time 2017-06-11 21:38:53.405770 
loop 2 time 2017-06-11 21:38:53.406243 
loop 1 time 2017-06-11 21:38:56.409524 
loop 2 time 2017-06-11 21:38:56.410034 
loop 1 time 2017-06-11 21:38:59.413300 
loop 2 time 2017-06-11 21:38:59.413846 

我對以上程序

  1. 在這種情況下,下面的問題被認爲是協程的函數print_time(如在包含yield聲明?

  2. does_future()每次調用時都會創建一個單獨的任務/進程?從這個意義上說,它類似於叉()

  3. 當前循環運行永遠。在10次迭代之後,我如何優雅地退出?

回答

1
  1. 在這種情況下被認爲是協程的功能print_time(如包含yield語句?

當你需要它(例如,您可以創建功能協同程序,如果它應該等待另一個協程)。對於create協程,您應該使用特殊修飾器@asyncio.coroutine(或者在Python 3.5+中使用async def定義協程):

@asyncio.coroutine 
def print_time(number, loop): 
    ... 

在你的情況發生器被認爲是協程只是因爲asyncio的協程使用發生器實現。你不應該使用普通的生成器作爲協程,而應該總是明確地使用裝飾器@asyncio.coroutine(或async def)來創建協程。

  1. does ensure_future()每次調用它時都會創建一個單獨的任務/進程?在這個意義上是它類似於叉()

ensure_future不創建OS線程或進程。通常,所有的協同程序/任務都在單個操作系統線程中運行,即單個進程。

ensure_future是一種規則執行異步腳本流程的方法。當你只等待一些協程時,它下面的代碼只有在協程完成後才能運行。 ensure_future允許你"run coroutine in background"沒有阻止它下面的執行代碼。

實施例1:

yield from coro_1() 
yield from coro_2() # this line would be started only after coro_1 finished. 

實施例2:

asyncio.ensure_future(coro_1()) 
yield from coro_2() # this line would be started immediately. 
        # coro_1 and coro_2 would de facto run parallely. 
  • 電流回路正在運行永遠。在10次迭代之後,我如何優雅地退出?
  • 有很多方法可以做到這一點,具體取決於您希望代碼的工作方式。

    這裏有一個,例如:

    from datetime import datetime 
    import asyncio 
    
    
    # We should somehow limit number of iterations for this coroutine. 
    # For example we can pass it as param 'tries': 
    @asyncio.coroutine 
    def print_time(number, loop, tries): 
        et = loop.time() + 10.0 
        for _ in range(tries): 
         print('loop {} time {}'.format(number, datetime.now())) 
         if (loop.time() >= et): 
          break 
         yield from asyncio.sleep(3) 
    
    
    @asyncio.coroutine 
    def main(): 
    
        # Run to tasks parallely and await both done using 'asyncio.gather': 
        yield from asyncio.gather(
         asyncio.ensure_future(print_time(1, loop, tries=5)), 
         asyncio.ensure_future(print_time(2, loop, tries=5)) 
        ) 
    
    
    loop = asyncio.get_event_loop() 
    
    # Use 'run_until_complete' to finish execution when some coroutine is done: 
    loop.run_until_complete(main()) 
    

    輸出:

    loop 1 time 2017-06-11 15:16:03.864059 
    loop 2 time 2017-06-11 15:16:03.864059 
    loop 1 time 2017-06-11 15:16:06.864826 
    loop 2 time 2017-06-11 15:16:06.864826 
    loop 1 time 2017-06-11 15:16:09.865046 
    loop 2 time 2017-06-11 15:16:09.865046 
    loop 1 time 2017-06-11 15:16:12.865199 
    loop 2 time 2017-06-11 15:16:12.865199 
    loop 1 time 2017-06-11 15:16:15.865978 
    loop 2 time 2017-06-11 15:16:15.865978 
    [Finished in 12.2s]