轉(zhuǎn)帖|使用教程|編輯:黃竹雯|2019-04-15 11:18:30.000|閱讀 568 次
概述:淺談Python中的協(xié)程及利用協(xié)程代替多線(xiàn)程及多進(jìn)程并發(fā)編程,與大家分享協(xié)程的魅力。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷(xiāo)售中 >>
相關(guān)鏈接:
協(xié)程定義說(shuō)的清楚明了的文章不是很多,手頭上有幾本Python相關(guān)的書(shū)籍,其中《流暢的Python》一書(shū)中解釋協(xié)程的定義是小編認(rèn)為最簡(jiǎn)單明了的。
Python協(xié)程魅力-利用協(xié)程代替多線(xiàn)程源碼下載
乍看生成器和協(xié)程長(zhǎng)的可真像,因?yàn)槎加玫搅藋ield關(guān)鍵字,那么問(wèn)題來(lái)了,如何區(qū)分二者?
def cd(n): print("Counting down from %s" % n) while n > 0: yield n n -= 1 c = cd(10) next(c) for i in c : print(i,end=' ')
上面是一個(gè)典型的生成器函數(shù),我們稍加變化使之成為協(xié)程。
def cd1(): n = yield while n > 0: print("Counting down from %s" % n) n -= 1 c1 = cd1() next(c1) c1.send(10) #運(yùn)行到這里應(yīng)該拋出一個(gè)異常
生成器和協(xié)程的不同有沒(méi)有看出來(lái)?很明顯的有兩處:
通過(guò)運(yùn)行結(jié)果我們可以到最后拋出了一個(gè)異常StopIteration,然后結(jié)束了這個(gè)協(xié)程。我們可以考慮一下:用裝飾器省略掉next()這步,然后捕獲拋出的異常,再關(guān)閉掉協(xié)程函數(shù)。
from functools import wraps def coroutine(func): @wraps(func) def primer(*args, **kwargs): gen = func(*args,**kwargs) next(gen) return gen return primer @coroutine def cd2(): n = yield while n > 0: print("Counting down from %s" % n) n -= 1 try: cd2().send(10) except Exception as e: print('協(xié)程任務(wù)終止')
帶上了裝飾器,就更簡(jiǎn)便一些了,最后捕獲異常,就可以結(jié)束這個(gè)協(xié)程了。
我們想用生成器(協(xié)程)作為系統(tǒng)線(xiàn)程的替代方案來(lái)實(shí)現(xiàn)并發(fā)。協(xié)程有時(shí)也稱(chēng)為用戶(hù)級(jí)線(xiàn)程或綠色線(xiàn)程。————引自《Python Cookbook》 這里的協(xié)程用到了asyncio模塊,利用asyncio模塊實(shí)現(xiàn)了一個(gè)協(xié)程的并發(fā)。關(guān)于asyncio的實(shí)現(xiàn)原理,之后再研究一下。
import asyncio import time import threading def tn(func): '''定義一個(gè)程序運(yùn)行時(shí)間計(jì)算函數(shù)''' def wrapper(*args, **kwargs): start = time.time() # 起始時(shí)間 func(*args, **kwargs) # 要執(zhí)行的函數(shù) end = time.time() # 結(jié)束時(shí)間 print('程序運(yùn)行時(shí)間:{:.2f}ms'.format((end-start))) return wrapper def loop1(tname): print(tname+"循環(huán)loop1打印時(shí)間======" + time.ctime()) time.sleep(1) # @asyncio.coroutine async def loop2(tname):# async等同于@asyncio.coroutine print(tname+"循環(huán)loop1打印時(shí)間======" + time.ctime()) # yield from asyncio.sleep(1) await asyncio.sleep(1) # 等同于yield from @asyncio.coroutine def loop3(tname):# async等同于@asyncio.coroutine print(tname+"循環(huán)loop1打印時(shí)間======" + time.ctime()) yield from asyncio.sleep(1) # await asyncio.sleep(1) # 等同于yield from @tn def main(): print('多線(xiàn)程任務(wù)開(kāi)始執(zhí)行=====') threads = []#定義一個(gè)線(xiàn)程隊(duì)列 for i in range(5): t = threading.Thread(target=loop1, args=("thread"+str(i),)) threads.append(t) for i in range(5): threads[i].start() for i in range(5): threads[i].join() #協(xié)程并發(fā)測(cè)試 print('協(xié)程并發(fā)測(cè)試開(kāi)始======') loop = asyncio.get_event_loop()# 獲取一個(gè)event_loop #任務(wù)列表 tasks = [ asyncio.ensure_future(loop2('11111')), asyncio.ensure_future(loop2('22222')), asyncio.ensure_future(loop2('33333')), asyncio.ensure_future(loop3('44444')),#loop3 asyncio.ensure_future(loop3('55555'))]#loop3 loop.run_until_complete(asyncio.wait(tasks)) loop.close() if __name__ == '__main__': main()
上邊這組代碼稍稍有點(diǎn)亂,可能你需要認(rèn)真的理下思緒,對(duì)比一下結(jié)果,你會(huì)發(fā)現(xiàn)雖然后邊執(zhí)行的代碼沒(méi)有利用多線(xiàn)程,但打印結(jié)果上的時(shí)間和多線(xiàn)程的執(zhí)行結(jié)果是一樣的。 這就是協(xié)程的魅力所在,一條線(xiàn)程搞定多線(xiàn)程任務(wù)。
【專(zhuān)業(yè)Python IDE推薦】——PyCharm (正版低至¥1068):
PyCharm 是一款Python IDE,其帶有一整套可以幫助用戶(hù)在使用Python語(yǔ)言開(kāi)發(fā)時(shí)提高其效率的工具。此外,該IDE提供了一些高級(jí)功能,以用于Django框架下的專(zhuān)業(yè)Web開(kāi)發(fā)。
PyCharm基礎(chǔ)教程推薦:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@ke049m.cn