併發程式設計 協程

2022-05-14 11:50:11 字數 3849 閱讀 2863

一 協程介紹

協程:是單執行緒下的併發,又稱微執行緒,纖程。英文名coroutine。一句話說明什麼是執行緒:協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的。、

需要強調的是:

對比作業系統控制線程的切換,使用者在單執行緒內控制協程的切換

優點如下:

缺點如下:

總結:必須在只有乙個單執行緒裡實現併發

修改共享資料不需加鎖

使用者程式裡自己儲存多個控制流的上下文棧

附加:乙個協程遇到io操作自動切換到其它協程(如何實現檢測io,yield、greenlet都無法實現,就用到了gevent模組(select機制))

二 greenlet模組

如果我們在單個執行緒內有20個任務,要想實現在多個任務之間切換,使用yield生成器的方式過於麻煩(需要先得到初始化一次的生成器,然後再呼叫send。。。非常麻煩),而使用greenlet模組可以非常簡單地實現這20個任務直接的切換

#

安裝:pip3 install greenlet

from greenlet import

greenlet

defeat(name):

print('

%s eat 1

' %name)

g2.switch(

'egon')

print('

%s eat 2

' %name)

g2.switch()

defplay(name):

print('

%s play 1

' %name)

g1.switch()

print('

%s play 2

' %name)

g1=greenlet(eat)

g2=greenlet(play)

g1.switch(

'egon

')#可以在第一次switch時傳入引數,以後都不需要

#單純的切換(在沒有io的情況下或者沒有重複開闢記憶體空間的操作),反而會降低程式的執行速度

#順序執行

import

time

deff1():

res=1

for i in range(100000000):

res+=i

deff2():

res=1

for i in range(100000000):

res*=i

start=time.time()

f1()

f2()

stop=time.time()

print('

run time is %s

' %(stop-start)) #

10.985628366470337#切換

from greenlet import

greenlet

import

time

deff1():

res=1

for i in range(100000000):

res+=i

g2.switch()

deff2():

res=1

for i in range(100000000):

res*=i

g1.switch()

start=time.time()

g1=greenlet(f1)

g2=greenlet(f2)

g1.switch()

stop=time.time()

print('

run time is %s

' %(stop-start)) #

52.763017892837524

greenlet

greenlet只是提供了一種比generator更加便捷的切換方式,當切到乙個任務執行時如果遇到io,那就原地阻塞,仍然是沒有解決遇到io自動切換來提公升效率的問題。

單執行緒裡的這20個任務的**通常會既有計算操作又有阻塞操作,我們完全可以在執行任務1時遇到阻塞,就利用阻塞的時間去執行任務2。。。。如此,才能提高效率,這就用到了gevent模組。

三 gevent模組

gevent 是乙個第三方庫,可以輕鬆通過gevent實現併發同步或非同步程式設計,在gevent中用到的主要模式是greenlet, 它是以c擴充套件模組形式接入python的輕量級協程。 greenlet全部執行在主程式作業系統程序的內部,但它們被協作式地排程。

#

用法g1=gevent.spawn(func,1,,2,3,x=4,y=5)建立乙個協程物件g1,spawn括號內第乙個引數是函式名,如eat,後面可以有多個引數,可以是位置實參或關鍵字實參,都是傳給函式eat的

g2=gevent.spawn(func2)

g1.join()

#等待g1結束

g2.join()

#等待g2結束

#或者上述兩步合作一步:gevent.joinall([g1,g2])

g1.value

#拿到func1的返回值

遇到io阻塞時會自動切換任務

import

gevent

defeat(name):

print('

%s eat 1

' %name)

gevent.sleep(2)

print('

%s eat 2

' %name)

defplay(name):

print('

%s play 1

' %name)

gevent.sleep(1)

print('

%s play 2

' %name)

g1=gevent.spawn(eat,'

egon')

g2=gevent.spawn(play,name='

egon')

g1.join()

g2.join()

#或者gevent.joinall([g1,g2])

print('

主')

上例gevent.sleep(2)模擬的是gevent可以識別的io阻塞,

而time.sleep(2)或其他的阻塞,gevent是不能直接識別的需要用下面一行**,打補丁,就可以識別了

from gevent import monkey;monkey.patch_all()必須放到被打補丁者的前面,如time,socket模組之前

或者我們乾脆記憶成:要用gevent,需要將from gevent import monkey;monkey.patch_all()放到檔案的開頭

from gevent import

monkey;monkey.patch_all()

import

gevent

import

time

defeat():

print('

eat food 1')

time.sleep(2)

print('

eat food 2')

defplay():

print('

play 1')

time.sleep(1)

print('

play 2')

g1=gevent.spawn(eat)

g2=gevent.spawn(play_phone)

gevent.joinall([g1,g2])

print('

主')

我們可以用threading.current_thread().getname()來檢視每個g1和g2,檢視的結果為dummythread-n,即假執行緒

python 併發程式設計 協程 協程介紹

協程 是單執行緒下的併發,又稱微執行緒,纖程。英文名coroutine。一句話說明什麼是執行緒 協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的 需要強調的是 1.python的執行緒屬於核心級別的,即由作業系統控制排程 如單執行緒遇到io或執行時間過長就會被迫交出cpu執行許可...

Python 併發程式設計(協程)

本章節主要介紹,使用單執行緒實現併發,即只用乙個主線程 很明顯可利用cpu只有乙個 為此我們需要先回顧下併發的本質 切換 儲存狀態 ps 在介紹程序理論時,提及程序的三種執行狀態,而執行緒才是執行單位,所以也可以將上圖理解為執行緒的三種狀態 單執行緒下併發稱為 協程 特點 缺點 gevent 是乙個...

併發程式設計之協程

協程 是單執行緒下的併發,一句話說明什麼是執行緒 協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的。對比作業系統控制線程的切換,使用者在單執行緒內控制協程的切換 優點 1.協程的切換開銷更小,屬於程式級別的切換,作業系統完全感知不到,因而更加輕量級 2.單執行緒內就可以實現併發的...