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