1. 程式人生 > >python並發編程之---協程

python並發編程之---協程

返回值 協程 strong 現在 沒有 麻煩 協作式 括號 內核級

1.什麽是協程

協程:是單線程下的並發,又稱微線程,纖程。

協程是一種用戶態的輕量級線程,協程是由用戶程序自己控制調度的。

2.需要註意的點:

需要強調的是:

#1. python的線程屬於內核級別的,即由操作系統控制調度(如單線程遇到io或執行時間過長就會被迫交出cpu執行權限,切換其他線程運行)
#2. 單線程內開啟協程,一旦遇到io,就會從應用程序級別(而非操作系統)控制切換,以此來提升效率(!!!非io操作的切換與效率無關)

對比操作系統控制線程的切換,用戶在單線程內控制協程的切換

優點如下:

#1. 協程的切換開銷更小,屬於程序級別的切換,操作系統完全感知不到,因而更加輕量級
#2. 單線程內就可以實現並發的效果,最大限度地利用cpu 缺點如下: #1. 協程的本質是單線程下,無法利用多核,可以是一個程序開啟多個進程,每個進程內開啟多個線程,每個線程內開啟協程 #2. 協程指的是單個線程,因而一旦協程出現阻塞,將會阻塞整個線程

3.協程的特點如下:

(1)必須在只有一個單線程裏實現並發

(2)修改共享數據不需加鎖

(3)用戶程序裏自己保存多個控制流的上下文棧

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

4.Greenlet

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

#安裝
pip3 install greenlet
from greenlet import greenlet

def eat(name):
    print(%s eat 1 %name)
    g2.switch(egon)
    print(%s eat 2 %name)
    g2.switch()
def play(name):
    print(%s play 1 %name)
    g1.switch()
    print(%s play 2 %name)

g1=greenlet(eat)
g2=greenlet(play)

g1.switch(
egon)#可以在第一次switch時傳入參數,以後都不需要

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

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

5.Gevent介紹

#安裝
pip3 install 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的返回值

要用gevent,需要將from gevent import monkey;monkey.patch_all()放到文件的開頭

from gevent import monkey;monkey.patch_all()

import gevent
import time
def eat():
    print(eat food 1)
    time.sleep(2)
    print(eat food 2)

def play():
    print(play 1)
    time.sleep(1)
    print(play 2)

g1=gevent.spawn(eat)
g2=gevent.spawn(play_phone)
gevent.joinall([g1,g2])
print()

python並發編程之---協程