經過async關鍵字定義一個協程(coroutine),協程也是一種對象。協程不能直接運行,須要把協程加入到事件循環(loop),由後者在適當的時候調用協程。asyncio.get_event_loop方法能夠建立一個事件循環,而後使用run_until_complete將協程註冊到事件循環,並啓動事件循環。python
import time import asyncio async def task(x): print('Waiting: ', x) await asyncio.sleep(x) start = time.time() coroutine = task(2) loop = asyncio.get_event_loop() loop.run_until_complete(coroutine) print('用時:', time.time()-start)
協程對象不能直接運行,在註冊事件循環的時候,實際上是run_until_complete方法將協程包裝成爲了一個任務(task)對象。所謂task對象是Future類的子類。保存了協程運行後的狀態,用於將來獲取協程的結果。程序員
import asyncio import time async def task(x): print('Waiting: ', x) await asyncio.sleep(x) start = time.time() coroutine = task(2) loop = asyncio.get_event_loop() task = loop.create_task(coroutine) # task = asyncio.ensure_future(coroutine) print(task) loop.run_until_complete(task) print(task) print('用時:', time.time() - start)
建立task後,task在加入事件循環以前是pending狀態,執行以後是finished狀態。網絡
asyncio.ensure_future(coroutine) 和loop.create_task(coroutine)
均可以建立一個task,run_until_complete的參數是一個futrue對象。當傳入一個協程,其內部會自動封裝成task,task是Future的子類。isinstance(task, asyncio.Future)將會輸出True。併發
綁定回調,在task執行完畢的時候能夠獲取執行的結果,回調的最後一個參數是future對象,經過該對象能夠獲取協程返回值。若是回調須要多個參數,能夠經過偏函數導入。異步
import time import asyncio async def task(x): print('Waiting: ', x) await asyncio.sleep(x) return 'Done after {}s'.format(x) def callback(future): print('Callback: ', future.result()) coroutine = task(2) loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine) task.add_done_callback(callback) loop.run_until_complete(task)
coroutine執行結束時候會調用回調函數。並經過參數future獲取協程執行的結果。咱們建立的task和回調裏的future對象,其實是同一個對象。async
回調中咱們使用了future對象的result方法。前面不綁定回調的例子中,咱們能夠看到task有fiinished狀態。在那個時候,能夠直接讀取task的result方法。函數
async def task(x): print('Waiting {}'.format(x)) return 'Done after {}s'.format(x) coroutine = task(2) loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine) loop.run_until_complete(task) # task.result()是協程對象的返回值 print('Task result: {}'.format(task.result()))
使用async能夠定義協程對象,使用await能夠針對耗時的操做進行掛起,就像生成器裏的yield同樣,函數讓出控制權。協程遇到await,事件循環將會掛起該協程,執行別的協程,直到其餘的協程也掛起或者執行完畢,再進行下一個協程的執行。oop
耗時的操做通常是一些IO操做,例如網絡請求,文件讀取等。咱們使用asyncio.sleep函數來模擬IO操做。協程的目的也是讓這些IO操做異步化。code
import asyncio import time async def task(x): print('Waiting: ', x) await asyncio.sleep(x) return 'Done after {}s'.format(x) start = time.time() coroutine = task(2) loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine) loop.run_until_complete(task) print('Task result: ', task.result()) print('Time: ', time.time() - start)
在 sleep的時候,使用await讓出控制權。即當遇到阻塞調用的函數的時候,使用await方法將協程的控制權讓出,以便loop調用其餘的協程。如今咱們的例子就用耗時的阻塞操做了。orm
asyncio實現併發,就須要多個協程來完成任務,每當有任務阻塞的時候就await,而後其餘協程繼續工做。建立多個協程的列表,而後將這些協程註冊到事件循環中。
import asyncio import time async def task(x): print('Waiting: ', x) await asyncio.sleep(x) return 'Done after {}s'.format(x) start = time.time() coroutine1 = task(1) # <coroutine object task at 0x000001E583341258> coroutine2 = task(2) coroutine3 = task(4) loop = asyncio.get_event_loop() tasks = [ # 建立任務 asyncio.ensure_future(coroutine1), asyncio.ensure_future(coroutine2), asyncio.ensure_future(coroutine3) ] loop.run_until_complete(asyncio.wait(tasks)) for task in tasks: print('Task result: ', task.result()) print('Time: ', time.time() - start) # 當任務比較多的時候,可使用列表生成式,效果是同樣的。 import asyncio import time async def task(x): print('Waiting: ', x) await asyncio.sleep(x) return 'Done after {}s'.format(x) start = time.time() loop = asyncio.get_event_loop() tasks = [asyncio.ensure_future(task(i)) for i in [1,2,4]] loop.run_until_complete(asyncio.wait(tasks)) for task in tasks: print('Task result: ', task.result()) print('Time: ', time.time() - start)
使用aysncio實現了併發。asyncio.wait(tasks) 也可使用 asyncio.gather(*tasks) ,前者接受一個task列表,後者接收一堆task。