python协程库_python中协程的详解(附示例)
本篇文章給大家?guī)淼膬?nèi)容是關(guān)于python中協(xié)程的詳解(附示例),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。
協(xié)程,又稱微線程,纖程。英文名Coroutine
協(xié)程看上去也是子程序,但執(zhí)行過程中,在子程序內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序,在適當(dāng)?shù)臅r(shí)候再返回來接著執(zhí)行。
最大的優(yōu)勢就是協(xié)程極高的執(zhí)行效率。因?yàn)樽映绦蚯袚Q不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數(shù)量越多,協(xié)程的性能優(yōu)勢就越明顯。
第二大優(yōu)勢就是不需要多線程的鎖機(jī)制,因?yàn)橹挥幸粋€(gè)線程,也不存在同時(shí)寫變量沖突,在協(xié)程中控制共享資源不加鎖,只需要判斷狀態(tài)就好了,所以執(zhí)行效率比多線程高很多。
因?yàn)閰f(xié)程是一個(gè)線程執(zhí)行,那怎么利用多核CPU呢?最簡單的方法是多進(jìn)程+協(xié)程,既充分利用多核,又充分發(fā)揮協(xié)程的高效率,可獲得極高的性能。
yield實(shí)現(xiàn)協(xié)程
Python對(duì)協(xié)程的支持還非常有限,用在generator中的yield可以一定程度上實(shí)現(xiàn)協(xié)程。雖然支持不完全,但已經(jīng)可以發(fā)揮相當(dāng)大的威力了。
import threading import time def producer(c): c.__next__() n=0 while n<5: n+=1 print('[生產(chǎn)者]產(chǎn)出第%s條數(shù)據(jù)' %(n)) res = c.send(n) print('[返回]:%s' %(res)) def consumer(): r='sheenstar' while True: # 更新r值: r = 'This is ok!', c.__next__() # n= yield r --> c.send(n) --> n更新 n = yield r if not n: break print('[消費(fèi)者]正在調(diào)用第%s條數(shù)據(jù)' %(n)) time.sleep(1) r = 'This is ok!' if __name__=='__main__': print(threading.current_thread()) print(threading.active_count()) #查看當(dāng)前進(jìn)行的線程 c = consumer() producer(c) #函數(shù)中有yield, 返回值為生成器; print(threading.active_count()) #1
gevent庫實(shí)現(xiàn)協(xié)程
Python通過yield提供了對(duì)協(xié)程的基本支持,但是不完全。而第三方的gevent為Python提供了比較完善的協(xié)程支持。
gevent是第三方庫,通過greenlet實(shí)現(xiàn)協(xié)程,其基本思想是:
當(dāng)一個(gè)greenlet遇到IO操作時(shí),比如訪問網(wǎng)絡(luò),就自動(dòng)切換到其他的greenlet,等到IO操作完成,再在適當(dāng)?shù)臅r(shí)候切換回來繼續(xù)執(zhí)行。由于IO操作非常耗時(shí),經(jīng)常使程序處于等待狀態(tài),有了gevent為我們自動(dòng)切換協(xié)程,就保證總有g(shù)reenlet在運(yùn)行,而不是等待IO。
由于切換是在IO操作時(shí)自動(dòng)完成,所以gevent需要修改Python自帶的一些標(biāo)準(zhǔn)庫,這一過程在啟動(dòng)時(shí)通過monkey patch完成。
假設(shè)多協(xié)程執(zhí)行的任務(wù), 沒有IO操作或者等待, 那么協(xié)程間是依次運(yùn)行, 而不是交替運(yùn)行;
假設(shè)多協(xié)程執(zhí)行的任務(wù), IO操作或者等待, 那么協(xié)程間是交替運(yùn)行;
#沒有等待 import gevent from gevent import monkey monkey.patch_all() def job(n): for i in range(n): print(gevent.getcurrent(),i) def mian(): g1 = gevent.spawn(job,1) g2 = gevent.spawn(job,2) g3 = gevent.spawn(job,3) gevent.joinall([g1,g2,g3]) print('協(xié)程執(zhí)行任務(wù)結(jié)束...') if __name__=="__main__": mian()
""" #有等待 import time from gevent import monkey monkey.patch_all() import gevent def job(n): for i in range(n): print(gevent.getcurrent(), i) time.sleep(1) def main1(): # 創(chuàng)建三個(gè)協(xié)程, 并讓該協(xié)程執(zhí)行job任務(wù) g1 = gevent.spawn(job, 2) g2 = gevent.spawn(job, 3) g3 = gevent.spawn(job, 2) # 等待所有的協(xié)程執(zhí)行結(jié)束, 再執(zhí)行主程序; gevent.joinall([g1, g2, g3]) print("任務(wù)執(zhí)行結(jié)束.....") main1()
協(xié)程與線程
做一個(gè)關(guān)于協(xié)程和線程花費(fèi)時(shí)間的對(duì)比實(shí)驗(yàn),不具有參考性 。
import time import gevent #導(dǎo)入?yún)f(xié)程 from gevent import monkey from urllib.request import urlopen #連接網(wǎng)絡(luò) from mytimeit import timeit #導(dǎo)入計(jì)算時(shí)間的裝飾器 from concurrent.futures import ThreadPoolExecutor #導(dǎo)入線程池 def get_len_url(url): with urlopen(url) as u_conn: data = u_conn.read() # print('%s該網(wǎng)頁共%s字節(jié)' %(url,len(data))) urls = ['http://httpbin.org', 'http://example.com/']*100 @timeit def coroutineall(): gevents = [gevent.spawn(get_len_url,url) for url in urls] gevent.joinall(gevents) @timeit def threadall(): with ThreadPoolExecutor(max_workers=100) as thpool: thpool.map(get_len_url,urls) if __name__=="__main__": coroutineall() threadall()
閱讀全文
1 個(gè)人已贊贊一個(gè)收藏 (0)打賞
您入群打賞務(wù)必備注QQ號(hào)
支付寶掃一掃贊助
微信錢包掃描贊助
分享到:
生成海報(bào)
評(píng)論 搶沙發(fā)
評(píng)論前必須登錄!
總結(jié)
以上是生活随笔為你收集整理的python协程库_python中协程的详解(附示例)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实现dns劫持_Python
- 下一篇: python准备_python环境准备