Python中協(xié)程coroutine適用場景分析
一、協(xié)程和線程的比較及其適用場景
1 共用變量問題
多線程中可能出現(xiàn)多個線程爭搶變量,所以變量需要加鎖;協(xié)程中任一時刻都只有一個線程,所以變量不需要加鎖。
但是協(xié)程雖然不像多線程爭搶變量但仍是和多線程一樣共用變量的,即共用變量在某處改變在另外一處引用時也會發(fā)生改變。
2 協(xié)程的適用場景
從資源角度說,協(xié)程只有一個線程只能使用一個cpu核,所以它適合用于IO密集(包括磁盤IO和網(wǎng)絡(luò)IO)函數(shù),并不適用于計算密集函數(shù)。
從事情重復性說,協(xié)程類似多線程,適用于被反復調(diào)用的函數(shù)(for或while),也可用于做不同事情的多個函數(shù)。
3 協(xié)程的切換
線程是由操作系統(tǒng)來控制切換的,并不需要我們自己來調(diào)度;但協(xié)程在操作系統(tǒng)中表現(xiàn)為一個線程,其調(diào)度操作系統(tǒng)無能為力,只得我們自己來實現(xiàn)。
await關(guān)鍵字表示該位置阻塞時可讓出cpu執(zhí)行,即切換到下一協(xié)程運行;但追根究底對我們而言好像只有await asyncio.sleep()(另外還有future但這個暫不考慮吧)。
所以各協(xié)程間一定要在某個地方(尤其是循環(huán)內(nèi))使用await asyncio.sleep()謙讓給其他協(xié)程,不然如果協(xié)程一直不謙讓那其他協(xié)程,那其他協(xié)程只能等該協(xié)程運行完才能運行了。
二、協(xié)程代碼實現(xiàn)
1 協(xié)程函數(shù)的定義
正常函數(shù)怎么寫就怎么寫,在def前面加上async即可。如:
async def say_after(delay, what): await asyncio.sleep(delay) print(what)
2 協(xié)程函數(shù)的調(diào)用
入口函數(shù)使用asyncio.run() 進行調(diào)用。如:
import asyncio async def main(): print(f"started at {time.strftime('%X')}") print('hello world!') print(f"finished at {time.strftime('%X')}") if __name__ == "__main__": # 入口函數(shù)通過asyncio.run()調(diào)用 asyncio.run(main())
一般協(xié)程函數(shù)調(diào)用時在其前面加上await關(guān)鍵字進行調(diào)用:
import asyncio import time async def say_after(delay, what): await asyncio.sleep(delay) print(what) async def main(): print(f"started at {time.strftime('%X')}") # 在前面加上await進行調(diào)用 # 這種形式和正常的同步執(zhí)行程序效果上沒什么區(qū)別,仍是執(zhí)行完上一步再執(zhí)行下一步 await say_after(1, 'hello') await say_after(2, 'world') print(f"finished at {time.strftime('%X')}") if __name__ == "__main__": # 入口函數(shù)通過asyncio.run()調(diào)用 asyncio.run(main())
最后一種是通過asyncio.create_task()
調(diào)用一般協(xié)程函數(shù)。
第二種調(diào)用方式也是調(diào)用一般協(xié)程函數(shù),但是如果只是這么調(diào)用的話協(xié)程函數(shù)并沒有什么作用,比如上邊這個函數(shù)耗時仍然和正常的同步版本一樣是3秒。
協(xié)程的意義在正在于asyncio.create_task()
調(diào)用形式,asyncio.create_task()
可以將協(xié)程函數(shù)包裝成任務(wù),多個任務(wù)之間可并行執(zhí)行。如下寫法只耗時2秒。
import asyncio import time #學習中遇到問題沒人解答?小編創(chuàng)建了一個Python學習交流群:153708845 class TestAsync: async def say_after(self,delay, what): await asyncio.sleep(delay) print(what) async def main(self): print(f"started at {time.strftime('%X')}") task_list = [] # 等價于[1,2] for i in range(1, 3, 1): # 步驟一、使用asyncio.create_task()調(diào)用協(xié)程函數(shù),封裝成任務(wù) tmp_task = asyncio.create_task(self.say_after(i, 'hello')) task_list.append(tmp_task) # 第二步,await任務(wù) for tmp_task in task_list: await tmp_task print(f"finished at {time.strftime('%X')}") if __name__ == "__main__": obj = TestAsync() asyncio.run(obj.main())
到此這篇關(guān)于Python中協(xié)程(coroutine)詳解的文章就介紹到這了,更多相關(guān)Python協(xié)程coroutine內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python函數(shù)實現(xiàn)學員管理系統(tǒng)
這篇文章主要為大家詳細介紹了Python函數(shù)實現(xiàn)學員管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07pytorch使用過程中遇到的錯誤處理之內(nèi)存溢出問題
這篇文章主要介紹了pytorch使用過程中遇到的錯誤處理之內(nèi)存溢出問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09python爬蟲將js轉(zhuǎn)化成json實現(xiàn)示例
這篇文章主要為大家介紹了python爬蟲將js轉(zhuǎn)化成json實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-05-05python使用pycharm環(huán)境調(diào)用opencv庫
這篇文章主要介紹了python使用pycharm環(huán)境調(diào)用opencv庫,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02