Python學習筆記 協程

2021-06-28 14:30:39 字數 3061 閱讀 3306

二十:協程:

協程,又稱微執行緒,纖程,coroutine

子程式 又稱為函式 在所有語言中都是層級呼叫 a呼叫b b呼叫c  c返回b b 返回 a 

所以子程式呼叫是通過棧實現的 乙個執行緒就是執行乙個子程式

子程式呼叫總是乙個入口 一次返回 呼叫順序是明確的 而協程的呼叫和子程式不同 

協程看上去也是子程式 但是執行過程中 在子程式內部可中斷 轉而執行別的子程式 在適當的時候在返回來接著執行 

注意 在乙個程式中中斷 去執行其他的子程式 不是函式呼叫 有點類似cpu的中斷 比如子程式ab

def a()

print '1'

print '2'

print '3'

def b()

print 'x'

print 'y'

print 'z'

假設由協程執行 在執行過程中 可以隨時中斷 去執行b b也可能在執行的過程中中斷去執行a 結果可能是

1  2  x  y 3 z

但是在a中沒有呼叫b 所以協程呼叫比函式理解更難

看起來像是多執行緒 但是協程的特點在於是乙個執行緒執行 那和多執行緒比 協程的優勢是:

最大的優勢是:協程的執行效率極高,因為子程式切換不是執行緒切換 而是有程式自身控制,因此 沒有執行緒切換的開銷 和多執行緒比執行緒數量越多 協程的效能優勢越大

其次就是不需要多執行緒的鎖機制 因為只有乙個執行緒

因為協程是乙個執行緒執行 如何利用多核cpu?最簡單的方法就是 多程序+協程 

python對協程的支援非常有限 用generator的yield可以一定程度實現協程

生產者-消費者問題 乙個執行緒寫訊息 乙個執行緒取訊息 通過鎖機制控制佇列和等待 但一不小心就可能鎖死

如果改用協程 生產者生產訊息 直接通過yield跳轉到消費者開始執行 待消費者執行完畢後 切換回生產者繼續生產

import time

def consumer():

r=''

while true:

n=yield r

if not n:

return 

print('[consumer] consuming %s...' % n)

time.sleep(1)

r='200 ok'

def produce(c):

c.next()

n=0while n<5:

n=n+1

print('[producer] producing .%s..' % n) 

r=c.send(n)

print('[producer] consumer return :%s ' % r)

c.close()

if __name__=='__main__':

c=consumer()

produce(c)

結果是 沒生產完乙個消費乙個 

注意到consumer函式是以個generator生成器 把乙個consumer傳入到produce後 

1:首先呼叫 c.next()啟動器

2:然後 一旦生產了東西 通過c.send(n) 切換到consumer執行

3:consumer通過yield得到訊息 處理 有通過yield把結果返回

4:produce拿到consumer處理的結果 繼續生產嚇一跳訊息

5:produce決定不生產了 通過從c.close()關閉consumer 整個過程結束 

2:gevent

python通過yield提供了對協程的基本支援 但是不完全 而第三方的gevent 為python提供了比較完善的協程支援

gevent是第三方庫 通過greenlet 實現協程 基本思想是:

當乙個greenlet 遇到io操作時 比如訪問網路的時候  就自動切換到其他的greenlet 等到io操作完成 再在適當的時候切換回來繼續執行 就保證總有greenlet在執行 而不是等待io

由於切換是在io操作中自動完成的 所以gevent需要修改python自帶的一些標準庫 這一過程在啟動時通過monkey patch 完成

from gevent import monkey;monkey.patch_socket()

import gevent

def f(n):

for i in range(n):

print gevent.getcurrent(),i

g1=gevent.spawn(f,5)

g2=gevent.spawn(f,5)

g3=gevent.spawn(f,5)

g1.join()

g2.join()

g3.join()

執行結果是 。。。。。。0

。。。。。。1

。。。。。。2    34  01234  01234

發現3個greenlet 是一次執行 不是交替執行

要讓greenlet 交替執行 通過 gevent.sleep() 交出控制權

def f(n):

for i in range(n):

print gevent.getcurrent(),

i gevent.sleep(0)

會發現是交替執行 000 111 222 333 444 555

而在實際中是不會用gevent.sleep() 去切換協程 而是執行io操作時 gevent自動切換

from gevent import monkey;monkey.patch_all()

import gevent

import urllib2

def f(url):

print('get:%s' %url)

resp=urllib2.urlopen(url)

data=resp.read()

print('%d bytes received from %s' %(len(data),url))

gevent.joinall([

gevent.spawn(f,'')

gevent.spawn(f,'')

gevent.spawn(f,'') ])

只能在unix或者linux上安裝執行 windows下面不可以

python學習筆記 協程

協程 協程是一種允許在特定位置暫停或恢復的子程式 這一點和生成器相似。但和生成器不同的是,寫成可以控制子程式暫停之後 的走向,而生成器僅能被動的將控制權交還給呼叫者。練習1 假設有兩個子程式main和printer。printer是乙個死迴圈,等待輸入 加工並輸出結果。main作為主程式,不時地向p...

Python 學習筆記 協程

python裡面控制併發,除了多執行緒和多程序,還可以使用協程 coroutine 他是在乙個執行緒內通過程式設計師人為的指定來進行切換 例1 通過switch 可以人為來回切換到另外乙個函式 當所有函式執行完畢,最後輸出print 10 usr bin env python coding utf ...

Python學習筆記 協程

協程 為非搶占式多工產生子程式的計算機元件,協程允許不同入口點在不同位置暫停或開始執行程式 從技術角度上講,是乙個可以暫停執行的函式,生成器 實現 1.yield返回 2.send呼叫 協程的四個狀態 inspect.getgeneratorstate 函式確定,該函式會返回下述字串的乙個 gen ...