python中重要的模块asyncio
生活中,假設 你是一家制造汽車的老板,員工點擊設備的【開始】按鈕之后,在設備前需等待30分鐘,然后點擊【結束】按鈕,此時作為老板的你一定希望這個員工在等待的那30分鐘的時間去做點其他的工作。
模塊asyncio用于編寫協程代碼,下面利用代碼來還原生活中的例子。
定義一個協程
協程(Coroutine),也可以被稱為微線程,是一種用戶態內的上下文切換技術。簡而言之,其實就是通過一個線程實現代碼塊相互切換執行。
形式為: async def的函數。使用async修飾將普通函數包裝成異步函數,直接調用異步函數不會返回結果,而是返回一個協程(coroutine)對象;
事件循環
協程對象不能直接運行,需要將協程加入到事件循環loop中。
創建一個事件循環loop
在主線程里,如果沒有被設置過任何事件循環,那么調用asyncio.get_event_loop()會創建一個事件循環并返回;
其他線程里需要首先loop=new_event_loop(),然后set_event_loop(loop).
將協程注冊到事件循環,并啟動事件循環
調用loop.run_until_complete(task)將協程加入到事件循環loop中,并啟動事件循環,直到協程(task)執行完成之后終止
在注冊事件循環的時候,run_until_complete(task)方法需要一個任務(task)對象,task對象是Future類的子類,保存了協程運行后的狀態,用于未來獲取協程的結果。
創建一個task
task = asyncio.ensure_future(coroutine) #創建task print('Task:', task) #Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py>>loop.run_until_complete(task) #將協程當做任務提交到事件循環的任務列表中,協程執行完成之后終止 print('Task:', task)#關閉事件循環 *** Task: <Task finished name='Task-1' coro=<request() done, defined at /Users/demo.py> 123可以通過asyncio.ensure_future(coroutine) 創建task,也可以通過loop.create_task(coroutine)創建task。
asyncio.ensure_future(coroutine):將一個coroutine對象包裝成Future對象;
**Future對象:**狀態:Pending、Running、Done、Cacelled;
創建future的時候,task為pending,
事件循環調用執行的時候當然就是running,
調用完畢自然就是done,
如果需要停止事件循環,中途需要取消,就需要先把task取消,即為cancelled。
綁定回調
在task執行完成的時候可以獲取執行的結果,回調函數的最后一個參數是future對象,通過該對象可以獲取協程返回值。
def callback(future):print('Status:', future.result()) #獲取協程返回值task = asyncio.ensure_future(coroutine) #創建task print('Task:', task) #Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py>> task.add_done_callback(callback) #給task任務綁定回調函數 print('Task:', task) #Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py:25> cb=[callback() at /Users/demo.py]>loop = asyncio.get_event_loop() #創建一個事件循環 print('Task:', task)#進入事件循環 Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py>>loop.run_until_complete(task) #將協程當做任務提交到事件循環的任務列表中,協程執行完成之后終止 print('Task:', task)#關閉事件循環 '''*** Status: 123 Task: <Task finished name='Task-1' coro=<request() done, defined at /Users/demo.py> result=123> '''print('Task Result:', task.result()) # Task Result: 123通過task.add_done_callback(callback)方法給task任務添加回調函數,當task(也可以說是coroutine)執行完成的時候,就會調用回調函數。并通過future,result()獲取協程執行的結果。
這里我們創建 的task和回調里的future對象實際上是同一個對象。
await
await是一個只能在協程函數中使用的關鍵字,用于遇到耗時(IO)的操作時事件循環將會掛起 當前協程(任務),去執行其他的協程(任務),直到其他的協程也掛起或者執行完畢,再進行下一個協程的執行。當前協程IO處理完成時,可以再次切換回來執行await之后的代碼。
耗時的操作一般是一些IO操作,例如網絡請求,文件讀取等。協程的目的也是讓這些IO操作異步化。
注意: await語法只能出現在通過async修飾的函數中,否則會報SyntaxError錯誤
這里耗時操作可使用asyncio.sleep函數來模擬IO操作
async def request(x):print("waiting:",x)# 當前協程掛起時,事件循環可以去執行其他協程(任務)。await asyncio.sleep(x)return 123協程來回切換執行的意義
計算型的操作,利用協程來回切換執行,沒有任何意義,來回切換并保存狀態 反倒會降低性能。
IO型的操作,利用協程在IO等待時間就去切換執行其他任務,當IO操作結束后再自動回調,那么就會大大節省資源并提供性能,從而實現異步編程(不等待任務結束就可以去執行其他代碼)。
協程一般應用在有IO操作的程序中,因為協程可以利用IO等待的時間去執行一些其他的代碼,從而提升代碼執行效率。
結合yield
參考:https://www.cnblogs.com/dhcn/p/9032461.html
import asyncio all_potatos = [1,2,3,4,5]#當生產者完成和返回之后,這是便能從await掛起的地方繼續往下跑,完成消費的過程。而這整一個過程,就是一個異步生成器迭代的流程 async def ask_for_potato():await asyncio.sleep(random.random())all_potatos.extend(Potato.make(random.randint(1, 10)))async def take_potatos(num):count = 0while True:if len(all_potatos) == 0:#當貨架上的土豆沒有了之后,我可以詢問超市請求需要更多的土豆,這時候需要等待一段時間直到生產者完成生產的過程await ask_for_potato()potato = all_potatos.pop()yield potatocount += 1if count == num:breakasync def buy_potatos():bucket = []#async for語法表示我們要后面迭代的是一個異步生成器。async for p in take_potatos(50):bucket.append(p)print('Got potato =',p)if __name__ == '__main__':loop = asyncio.get_event_loop()res = loop.run_until_complete(buy_potatos())loop.close()參考博客:
https://zhuanlan.zhihu.com/p/137057192
https://www.cnblogs.com/zhaof/p/8490045.html
https://blog.csdn.net/qq_27825451/article/details/86292513
https://zhuanlan.zhihu.com/p/69210021
總結
以上是生活随笔為你收集整理的python中重要的模块asyncio的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tf.control_dependenc
- 下一篇: 判断字符串是否回文