引自:https://blog.csdn.net/sunt2018/article/details/105138121
異步IO asyncio協程
asyncio 是python3.4 引入的,內置的對異步IO的支持。
asyncio編程是一個消息循環,我們從asyncio中獲取一個EventLoop引用
然后把協程放到EventLoop中執行,就實現了異步IO
協程常見名字
先了解以下名詞,有助於理解程序編寫
-
event_loop 事件循環: 程序開啟一個循環,我們把函數注冊到loop里,滿足條件就會執行
-
coroutine 協程: async def 定義的函數,它不能直接執行,返回的是
協程對象
,它要注冊到loop中,由loop去執行調用 -
task 任務: 一個協程對象就是一個原生可以掛起的函數,任務則是對協程對象進一步封裝,增加了任務的各種狀態,(比如未執行,執行中,執行結束,返回結果等等?。)
task 是 future的
子類
-
future : 代表將來執行或沒有執行的任務的結果,它個task沒有本質區別
-
async/await : python3.5 用於定義協程的關鍵字
創建一個協程 Coroutine
import asyncio,time # 記錄開始時間 now = lambda: time.time() start = now() # 01.定義一個協程 async def do_work(num): print("num:",num) coroutine = do_work(1) # 02.創建事件循環 loop = asyncio.get_event_loop() # 03.將協程對象放入事件循環中 loop.run_until_complete(coroutine) # 記錄結束時間 print(now() - start)
創建一個任務 Task
loop.run_until_complete方法傳入協程,自動將協程裝成任務task,它也可以直接接收task
創建task 使用以下方法都可以
asyncio.ensure_future(coroutine)
loop.create_task(coroutine)
task是future的子類。
isinstance(task,asyncio.Future) 返回Ture
import asyncio,time # 記錄開始時間 now = lambda: time.time() start = now() # 01.定義一個協程 async def do_work(num): print("num:",num) coroutine = do_work(1) # 02.創建事件循環 loop = asyncio.get_event_loop() # 03.創建任務Task task = asyncio.ensure_future(coroutine) # 或者下面的方式 創建task也可以 # task = loop.create_task(coroutine) # 04.將任務注冊到事件循環中 loop.run_until_complete(task) # 記錄結束時間 print(now() - start)
獲取返回結果 回調函數future/直接使用Task獲取
import asyncio,time # 記錄開始時間 now = lambda: time.time() start = now() # 01.定義一個協程 async def do_work(num): print("num:",num) return "num is {}".format(num) coroutine = do_work(3) # 02.定義回調函數 def callback(future): print('result is',future.result()) # 03.創建事件循環 loop = asyncio.get_event_loop() # 04.創建任務Task task = loop.create_task(coroutine) # 05.給task任務綁定回調函數 task.add_done_callback(callback) # 06.將任務注冊到事件循環中 loop.run_until_complete(task) # 記錄結束時間 print(now() - start)
不綁定回調,直接使用Task的結果
task.result()
,必須任務執行完畢后才有這個,不然會報錯
阻塞 await
import asyncio,time # 記錄開始時間 now = lambda: time.time() start = now() # 01.定義一個協程 async def do_work(num): print("num:",num) await asyncio.sleep(num) return "sleep is {}".format(num) coroutine = do_work(3) # 02.創建事件循環 loop = asyncio.get_event_loop() # 03.創建任務Task task = loop.create_task(coroutine) print(task.result()) # 04.將任務注冊到事件循環中 loop.run_until_complete(task) # 記錄結束時間 print(now() - start) print(task.result())
asyncio 實現並發
import asyncio,time # 記錄開始時間 now = lambda: time.time() start = now() # 01.定義一個協程 async def do_work(num): print("num:",num) await asyncio.sleep(num) return "sleep is {}".format(num) coroutine1 = do_work(1) coroutine2 = do_work(2) coroutine3 = do_work(3) # 02.創建任務Task tasks =[ asyncio.ensure_future(coroutine1), asyncio.ensure_future(coroutine2), asyncio.ensure_future(coroutine3), ] # 02.創建事件循環 loop = asyncio.get_event_loop() # 04.將任務注冊到事件循環中 loop.run_until_complete(asyncio.wait(tasks)) # 記錄結束時間 print(now() - start) for task in tasks: print(task.result())
協程嵌套
import time import asyncio async def do_work(x): print("do...work.....") await asyncio.sleep(x) return 'Done result' async def main(): # 創建多個協程對象 coroutine1 = do_work(1) coroutine2 = do_work(2) coroutine3 = do_work(4) tasks = [ asyncio.ensure_future(coroutine1), asyncio.ensure_future(coroutine2), asyncio.ensure_future(coroutine3) ] # -------------------------------------------- # 獲取返回結果的方式 1 dones,pendings = await asyncio.wait(tasks) # dones 是任務 for task in dones: print(task.result()) # -------------------------------------------- # 將協程main 放入到 loop中 loop = asyncio.get_event_loop() loop.run_until_complete(main())
獲取返回結果的方式2 results = await asyncio.gather(*tasks) for result in results(): print(result)
# 獲取方式3,不在main中獲取,而是在外面獲取 async def main: # ..... return await asyncio.gather(*tasks) results = loop.run_until_complete(main()) for result in results(): print(result)
# 獲取方式4,不在main中獲取,而是在外面獲取 async def main: # ..... return await asyncio.wait(tasks) dones,pendings = loop.run_until_complete(main()) for task in dones: print(task.result())
# 獲取方式5,還是在main中 for task in asyncio.as_complete(tasks): result = await task print(result)
協程的停止
future 中的幾種狀態
- Pending 創建future的時候,task為 pending
- Running 事件循環執行的時候,task是running
- Done 執行完畢 task狀態是done
- Cancelled 任務取消
-
import time import asyncio async def do_work(x): print("do...work.....") await asyncio.sleep(x) return 'Done result' coroutine1 = do_work(1) coroutine2 = do_work(2) coroutine3 = do_work(4) tasks = [ asyncio.ensure_future(coroutine1), asyncio.ensure_future(coroutine2), asyncio.ensure_future(coroutine3), ] start = time.time() loop = asyncio.get_event_loop() try: loop.run_until_complete(asyncio.wait(tasks)) except KeyboardInterrupt as e: for task in asyncio.Task.all_tasks(): print(task.cancel()) loop.stop() loop.run_forever() finally: loop.close() print(time.time() - start)