我們都知道執行緒間的任務切換是由作業系統來控制的,而協程的出現,就是為了減少作業系統的開銷,由協程來自己控制任務的切換
協程本質上就是執行緒。既然能夠切換任務,所以執行緒有兩個最基本的功能:一是儲存狀態;二是任務切換
8.8.1 協程的特點
【優點】
【缺點】
【特點】
8.8.2 greenlet
使用grennlet第三方庫實現任務間的切換
from greenlet import greenlet
def get_money(name):
print(f" get 10 $")
g2.switch('jiawen')
print(f" get 20 $")
g2.switch()
def buy_goods(name):
print(f" buy no.1 good ")
g1.switch()
print(f" buy no.2 good ")
g1.switch()
if __name__ == '__main__':
g1 = greenlet(get_money)
g2 = greenlet(buy_goods)
g1.switch('gailun') # switch在第一次時必須要傳入引數,以後就不需要了
效率對比
from greenlet import greenlet
import time
def f1():
re = 1
for i in range(10000000):
re *= i
g2.switch()
def f2():
re = 1
for i in range(10000000):
re += i
g1.switch()
if __name__ == '__main__':
start = time.time()
g1 = greenlet(f1)
g2 = greenlet(f2)
g1.switch() # switch在第一次時必須要傳入引數,以後就不需要了
print(f'') # 5.822627305984497
import time
def f1():
re = 1
for i in range(10000000):
re *= i
def f2():
re = 1
for i in range(10000000):
re += i
start = time.time()
f1()
f2()
print(f'') # 1.041489601135254
【結論】單純的切換,在沒有io阻塞的情況下,協程的效率反而降低
8.8.3 gevent介紹
gevent也是乙個第三方庫,主要用來實現併發同步或是非同步程式設計,在gevent中用到的主要模式是greenlet, greenlet全部執行在主程式作業系統程序的內部,但它們被協作式地排程。
【方法】
gevent.spawn(func,*args,**kwargs) spawn括號內第乙個引數是函式名,後面可以有多個引數,可以是位置實參或關鍵字實參,都是傳給函式func,spawn是非同步提交任務
join() 等待呼叫者結束
value() 拿到呼叫者的返回值
遇到io阻塞會自動切換
import gevent
def get_money(name):
print(f" get 10 $")
gevent.sleep(2) #模擬的是gevent可以識別的io阻塞
print(f" get 20 $")
def buy_goods(name):
print(f" buy no.1 good ")
gevent.sleep(1)
print(f" buy no.2 good ")
if __name__ == '__main__':
g1 = gevent.spawn(get_money,'gailun')
g2 = gevent.spawn(buy_goods,name='jiawen')
g1.join()
g2.join()
# gevent.joinall([g1,g2])
print('__main__')
# 輸出
gailun get 10 $
jiawen buy no.1 good
jiawen buy no.2 good
gailun get 20 $
__main__
【注意】如果要使gevent識別所有的io阻塞,放到被打補丁者的前面或者直接寫在在檔案的最開頭寫上以下**
rom gevent import monkey;monkey.patch_all()
應用
# 爬蟲
from gevent import monkey;monkey.patch_all()
import gevent
import requests
import time
def get_inf(url):
print(f'get:')
res = requests.get(url)
if res.status_code == 200:
print(f" get from ")
if __name__ == '__main__':
start_time = time.time()
gevent.joinall(
[gevent.spawn(get_inf,''),
gevent.spawn(get_inf,''),
gevent.spawn(get_inf,''),])
print(f"take secondes")
python學習 協程
在學習非同步io模型前,我們先來了解協程。協程,又稱微執行緒,纖程。英文名coroutine。協程的概念很早就提出來了,但直到最近幾年才在某些語言 如lua 中得到廣泛應用。子程式,或者稱為函式,在所有語言中都是層級呼叫,比如a呼叫b,b在執行過程中又呼叫了c,c執行完畢返回,b執行完畢返回,最後是...
Python之協程技術
1.定義 纖程,微執行緒。是允許在不同入口點不同位置暫停或開始的電腦程式,簡單來說,協程就是可以暫停執行的函式。2.協程原理 記錄乙個函式的上下文,協程排程切換時會將記錄的上下文儲存,在切換回來時進行調取,恢復原有的執行內容,以便從上一次執行位置繼續執行。協程本質上就是乙個執行緒,以前多執行緒任務的...
python之協程建立
協程,是充分利用cpu給該執行緒的時間,在乙個執行緒裡放置多個任務,當某個任務阻塞時就執行下乙個任務。其特點是能夠記住這些任務執行到哪一步了,下次再執行該任務的時候回從上次阻塞的地方繼續開始。建立協程需要使用gevent模組。如下 import gevent gevent協程中,遇到需要耗費時間的操...