摘要:協(xié)程,又稱微線程,纖程。最大的優(yōu)勢(shì)就是協(xié)程極高的執(zhí)行效率。生產(chǎn)者產(chǎn)出第條數(shù)據(jù)返回更新值更新消費(fèi)者正在調(diào)用第條數(shù)據(jù)查看當(dāng)前進(jìn)行的線程函數(shù)中有,返回值為生成器庫實(shí)現(xiàn)協(xié)程通過提供了對(duì)協(xié)程的基本支持,但是不完全。
協(xié)程,又稱微線程,纖程。英文名Coroutine
協(xié)程看上去也是子程序,但執(zhí)行過程中,在子程序內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序,在適當(dāng)?shù)臅r(shí)候再返回來接著執(zhí)行。
最大的優(yōu)勢(shì)就是協(xié)程極高的執(zhí)行效率。因?yàn)樽映绦蚯袚Q不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數(shù)量越多,協(xié)程的性能優(yōu)勢(shì)就越明顯。 第二大優(yōu)勢(shì)就是不需要多線程的鎖機(jī)制,因?yàn)橹挥幸粋€(gè)線程,也不存在同時(shí)寫變量沖突,在協(xié)程中控制共享資源不加鎖,只需要判斷狀態(tài)就好了,所以執(zhí)行效率比多線程高很多。 因?yàn)閰f(xié)程是一個(gè)線程執(zhí)行,那怎么利用多核CPU呢?最簡(jiǎn)單的方法是多進(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()) #1gevent庫實(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()
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/42587.html
摘要:協(xié)程實(shí)現(xiàn)連接在網(wǎng)絡(luò)通信中,每個(gè)連接都必須創(chuàng)建新線程或進(jìn)程來處理,否則,單線程在處理連接的過程中,無法接受其他客戶端的連接。所以我們嘗試使用協(xié)程來實(shí)現(xiàn)服務(wù)器對(duì)多個(gè)客戶端的響應(yīng)。 協(xié)程實(shí)現(xiàn)TCP連接 在網(wǎng)絡(luò)通信中,每個(gè)連接都必須創(chuàng)建新線程(或進(jìn)程) 來處理,否則,單線程在處理連接的過程中, 無法接受其他客戶端的連接。所以我們嘗試使用協(xié)程來實(shí)現(xiàn)服務(wù)器對(duì)多個(gè)客戶端的響應(yīng)。與單一TCP通信的構(gòu)架...
摘要:序列化標(biāo)簽有序標(biāo)簽和有序列表標(biāo)簽是,是一個(gè)雙標(biāo)簽。在每一個(gè)列表項(xiàng)目前要使用標(biāo)簽。標(biāo)簽的形式是帶有前后順序之分的編號(hào)。有序標(biāo)簽的屬性屬性用于設(shè)置編號(hào)為數(shù)字或者字母等的類型,如則編號(hào)用英文字母表示。通常是成對(duì)出現(xiàn)。 序列化標(biāo)簽 1.有序標(biāo)簽--ol和li 有序列表標(biāo)簽是,是一個(gè)雙標(biāo)簽。在每一個(gè)列表項(xiàng)目前要使用標(biāo)簽。標(biāo)簽的形式是帶有前后順序之分的編號(hào)。如果添加或者刪除一個(gè)列表項(xiàng),編號(hào)會(huì)自動(dòng)調(diào)...
摘要:序列化標(biāo)簽有序標(biāo)簽和有序列表標(biāo)簽是,是一個(gè)雙標(biāo)簽。在每一個(gè)列表項(xiàng)目前要使用標(biāo)簽。標(biāo)簽的形式是帶有前后順序之分的編號(hào)。有序標(biāo)簽的屬性屬性用于設(shè)置編號(hào)為數(shù)字或者字母等的類型,如則編號(hào)用英文字母表示。通常是成對(duì)出現(xiàn)。 序列化標(biāo)簽 1.有序標(biāo)簽--ol和li 有序列表標(biāo)簽是,是一個(gè)雙標(biāo)簽。在每一個(gè)列表項(xiàng)目前要使用標(biāo)簽。標(biāo)簽的形式是帶有前后順序之分的編號(hào)。如果添加或者刪除一個(gè)列表項(xiàng),編號(hào)會(huì)自動(dòng)調(diào)...
摘要:導(dǎo)航欄擁有易用的導(dǎo)航條對(duì)于任何網(wǎng)站都很重要。通過,您能夠把乏味的菜單轉(zhuǎn)換為漂亮的導(dǎo)航欄。導(dǎo)航欄需要標(biāo)準(zhǔn)的作為基礎(chǔ)。導(dǎo)航欄基本上是一個(gè)鏈接列表,因此使用和元素是非常合適的制作水平導(dǎo)航欄有兩種創(chuàng)建水平導(dǎo)航欄的方法。 導(dǎo)航欄 擁有易用的導(dǎo)航條對(duì)于任何網(wǎng)站都很重要。 通過 CSS,您能夠把乏味的 HTML 菜單轉(zhuǎn)換為漂亮的導(dǎo)航欄。 導(dǎo)航欄需要標(biāo)準(zhǔn)的 HTML 作為基礎(chǔ)。 在我們的例子中,將用標(biāo)...
摘要:是世界上最流行的腳本語言。是屬于的語言,它適用于筆記本電腦平板電腦和移動(dòng)電話。被設(shè)計(jì)為向頁面增加交互性。幾乎每個(gè)人都有能力將小的片段添加到網(wǎng)頁中。 JavaScript JavaScript 是世界上最流行的腳本語言。JavaScript 是屬于 web 的語言,它適用于 PC、筆記本電腦、平板電腦和移動(dòng)電話。JavaScript 被設(shè)計(jì)為向 HTML 頁面增加交互性。許多 HTML ...
閱讀 3694·2021-11-11 10:58
閱讀 2475·2021-09-22 15:43
閱讀 2867·2019-08-30 15:44
閱讀 2186·2019-08-30 13:08
閱讀 1820·2019-08-29 17:28
閱讀 884·2019-08-29 10:54
閱讀 674·2019-08-26 11:46
閱讀 3506·2019-08-26 11:43