摘要:協程,又稱微線程,纖程。最大的優勢就是協程極高的執行效率。生產者產出第條數據返回更新值更新消費者正在調用第條數據查看當前進行的線程函數中有,返回值為生成器庫實現協程通過提供了對協程的基本支持,但是不完全。
協程,又稱微線程,纖程。英文名Coroutine
協程看上去也是子程序,但執行過程中,在子程序內部可中斷,然后轉而執行別的子程序,在適當的時候再返回來接著執行。
最大的優勢就是協程極高的執行效率。因為子程序切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。 第二大優勢就是不需要多線程的鎖機制,因為只有一個線程,也不存在同時寫變量沖突,在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多。 因為協程是一個線程執行,那怎么利用多核CPU呢?最簡單的方法是多進程+協程,既充分利用多核,又充分發揮協程的高效率,可獲得極高的性能。yield實現協程
Python對協程的支持還非常有限,用在generator中的yield可以一定程度上實現協程。雖然支持不完全,但已經可以發揮相當大的威力了。
import threading import time def producer(c): c.__next__() n=0 while n<5: n+=1 print("[生產者]產出第%s條數據" %(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("[消費者]正在調用第%s條數據" %(n)) time.sleep(1) r = "This is ok!" if __name__=="__main__": print(threading.current_thread()) print(threading.active_count()) #查看當前進行的線程 c = consumer() producer(c) #函數中有yield, 返回值為生成器; print(threading.active_count()) #1gevent庫實現協程
Python通過yield提供了對協程的基本支持,但是不完全。而第三方的gevent為Python提供了比較完善的協程支持。
gevent是第三方庫,通過greenlet實現協程,其基本思想是: 當一個greenlet遇到IO操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。由于IO操作非常耗時,經常使程序處于等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在運行,而不是等待IO。
由于切換是在IO操作時自動完成,所以gevent需要修改Python自帶的一些標準庫,這一過程在啟動時通過monkey patch完成。
假設多協程執行的任務, 沒有IO操作或者等待, 那么協程間是依次運行, 而不是交替運行; 假設多協程執行的任務, IO操作或者等待, 那么協程間是交替運行;
#沒有等待 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("協程執行任務結束...") 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(): # 創建三個協程, 并讓該協程執行job任務 g1 = gevent.spawn(job, 2) g2 = gevent.spawn(job, 3) g3 = gevent.spawn(job, 2) # 等待所有的協程執行結束, 再執行主程序; gevent.joinall([g1, g2, g3]) print("任務執行結束.....") main1()協程與線程
做一個關于協程和線程花費時間的對比實驗,不具有參考性 。
import time import gevent #導入協程 from gevent import monkey from urllib.request import urlopen #連接網絡 from mytimeit import timeit #導入計算時間的裝飾器 from concurrent.futures import ThreadPoolExecutor #導入線程池 def get_len_url(url): with urlopen(url) as u_conn: data = u_conn.read() # print("%s該網頁共%s字節" %(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()
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/42587.html
摘要:協程實現連接在網絡通信中,每個連接都必須創建新線程或進程來處理,否則,單線程在處理連接的過程中,無法接受其他客戶端的連接。所以我們嘗試使用協程來實現服務器對多個客戶端的響應。 協程實現TCP連接 在網絡通信中,每個連接都必須創建新線程(或進程) 來處理,否則,單線程在處理連接的過程中, 無法接受其他客戶端的連接。所以我們嘗試使用協程來實現服務器對多個客戶端的響應。與單一TCP通信的構架...
摘要:序列化標簽有序標簽和有序列表標簽是,是一個雙標簽。在每一個列表項目前要使用標簽。標簽的形式是帶有前后順序之分的編號。有序標簽的屬性屬性用于設置編號為數字或者字母等的類型,如則編號用英文字母表示。通常是成對出現。 序列化標簽 1.有序標簽--ol和li 有序列表標簽是,是一個雙標簽。在每一個列表項目前要使用標簽。標簽的形式是帶有前后順序之分的編號。如果添加或者刪除一個列表項,編號會自動調...
摘要:序列化標簽有序標簽和有序列表標簽是,是一個雙標簽。在每一個列表項目前要使用標簽。標簽的形式是帶有前后順序之分的編號。有序標簽的屬性屬性用于設置編號為數字或者字母等的類型,如則編號用英文字母表示。通常是成對出現。 序列化標簽 1.有序標簽--ol和li 有序列表標簽是,是一個雙標簽。在每一個列表項目前要使用標簽。標簽的形式是帶有前后順序之分的編號。如果添加或者刪除一個列表項,編號會自動調...
摘要:導航欄擁有易用的導航條對于任何網站都很重要。通過,您能夠把乏味的菜單轉換為漂亮的導航欄。導航欄需要標準的作為基礎。導航欄基本上是一個鏈接列表,因此使用和元素是非常合適的制作水平導航欄有兩種創建水平導航欄的方法。 導航欄 擁有易用的導航條對于任何網站都很重要。 通過 CSS,您能夠把乏味的 HTML 菜單轉換為漂亮的導航欄。 導航欄需要標準的 HTML 作為基礎。 在我們的例子中,將用標...
摘要:是世界上最流行的腳本語言。是屬于的語言,它適用于筆記本電腦平板電腦和移動電話。被設計為向頁面增加交互性。幾乎每個人都有能力將小的片段添加到網頁中。 JavaScript JavaScript 是世界上最流行的腳本語言。JavaScript 是屬于 web 的語言,它適用于 PC、筆記本電腦、平板電腦和移動電話。JavaScript 被設計為向 HTML 頁面增加交互性。許多 HTML ...
閱讀 3702·2021-11-11 10:58
閱讀 2485·2021-09-22 15:43
閱讀 2875·2019-08-30 15:44
閱讀 2195·2019-08-30 13:08
閱讀 1826·2019-08-29 17:28
閱讀 892·2019-08-29 10:54
閱讀 681·2019-08-26 11:46
閱讀 3512·2019-08-26 11:43