我們通常所說的協程Coroutine其實是corporate routine的縮寫,直接翻譯爲協同的例程,一般我們都簡稱爲協程。
在linux系統中,執行緒就是輕量級的進程,而我們通常也把協程稱爲輕量級的執行緒即微執行緒。
下面 下麪對比一下進程和協程的相同點和不同點:
相同點:
而暫存器和棧的結合就可以理解爲上下文,上下文切換的理解:
CPU看上去像是在併發的執行多個進程,這是通過處理器在進程之間切換來實現的,操作系統實現這種交錯執行的機制 機製稱爲上下文切換
操作系統保持跟蹤進程執行所需的所有狀態資訊。這種狀態,就是上下文。
在任何一個時刻,操作系統都只能執行一個進程程式碼,當操作系統決定把控制權從當前進程轉移到某個新進程時,就會進行上下文切換,即儲存當前進程的上下文,恢復新進程的上下文,然後將控制權傳遞到新進程,新進程就會從它上次停止的地方開始。
不同點:
既然我們上面也說了,協程也被稱爲微執行緒,下面 下麪對比一下協程和執行緒:
協程只是在單一的執行緒裡不同的協程之間切換,其實和執行緒很像,執行緒是在一個進程下,不同的執行緒之間做切換,這也可能是協程稱爲微執行緒的原因吧。
Gevent模組是一種基於協程的Python網路庫,它用到Greenlet提供的,封裝了libevent事件回圈的高層同步API。它讓開發者在不改變程式設計習慣的同時,用同步的方式寫非同步I/O的程式碼。
如果想瞭解gevent的排程流程,最重要的是對greenlet有基本的瞭解。下面 下麪總結一些個人認爲比較重要的點:
在gevent中,有兩個類繼承了greenlet.greenlet,分別是gevent.hub.Hub和gevent.greenlet.Greenlet。後文中,如果是greenlet.greenlet這種寫法,那麼指的是原生的類庫greentlet,如果是greenlet(或者Greenlet)那麼指gevent封裝後的greenlet。
gevent中的主要模式, 它是以C擴充套件模組形式接入Python的輕量級協程。 全部執行在主程式操作系統進程的內部,但它們被程式設計師共同作業式地排程。
在任何時刻,只有一個協程在執行。
區別於multiprocessing、threading等提供真正並行構造的庫, 這些庫輪轉使用操作系統排程的進程和執行緒,是真正的並行。
基於libev的快速事件回圈(Linux上epoll,FreeBSD上kqueue)。
基於greenlet的輕量級執行單元。
API的概念和Python標準庫一致(如事件,佇列)。
可以配合socket,ssl模組使用。
能夠使用標準庫和第三方模組建立標準的阻塞通訊端(gevent.monkey)。
預設通過執行緒池進行DNS查詢,也可通過c-are(通過GEVENT_RESOLVER=ares環境變數開啓)。
TCP/UDP/HTTP伺服器
子進程支援(通過gevent.subprocess)
執行緒池
安裝和依賴
依賴於greenlet library
支援python 2.6+ 、3.3+
pip install gevent
#coding:utf-8
import time
from greenlet import greenlet
def eat():
print('魔降風雲變 is eating')
time.sleep(0.5)
print('魔降風雲變 finished eat')
def sleep():
print('小馬過河 is sleeping')
time.sleep(0.5)
print('小馬過河 finished sleep')
g1 = greenlet(eat)
g1.switch()
--------------結果:
魔降風雲變 is eating
魔降風雲變 finished eat
#coding:utf-8
import time
from greenlet import greenlet
def eat():
print('魔降風雲變 is eating')
g2.switch()
time.sleep(0.5)
print('魔降風雲變 finished eat')
def sleep():
print('小馬過河 is sleeping')
time.sleep(0.5)
print('小馬過河 finished sleep')
g1 = greenlet(eat)
g2 = greenlet(sleep)
g1.switch()
--------------結果:
魔降風雲變 is eating
小馬過河 is sleeping
小馬過河 finished sleep
#coding:utf-8
import time
from greenlet import greenlet
def eat():
print('魔降風雲變 is eating')
g2.switch()
time.sleep(0.5)
print('魔降風雲變 finished eat')
def sleep():
print('小馬過河 is sleeping')
time.sleep(0.5)
print('小馬過河 finished sleep')
g1.switch()
g1 = greenlet(eat)
g2 = greenlet(sleep)
g1.switch()
------------結果:
魔降風雲變 is eating
小馬過河 is sleeping
小馬過河 finished sleep
魔降風雲變 finished eat
``python
#coding:utf-8
import time
import gevent
def eat():
print('魔降風雲變 is eating')
time.sleep(1)
print('魔降風雲變 finished eat')
def sleep():
print('小馬過河 is sleeping')
time.sleep(1)
print('小馬過河 finished sleep')
g1 = gevent.spawn(eat) # 創造一個協程任務
-----------結果:沒有輸出
協程遇到阻塞才切換,這裏程式碼從上到下執行結束,沒有遇到阻塞
import time
import gevent
def eat():
print('魔降風雲變 is eating')
time.sleep(1)
print('魔降風雲變 finished eat')
def sleep():
print('小馬過河 is sleeping')
time.sleep(1)
print('小馬過河 finished sleep')
g1 = gevent.spawn(eat) # 創造一個協程任務
gevent.sleep(2) #加個gevent.sleep(2)就切換到eat執行裏面的程式碼了
---------結果:
魔降風雲變 is eating
魔降風雲變 finished eat
#加個gevent.sleep(2)就切換到eat執行裏面的程式碼了。eat中間time.sleep(1)照樣睡。
兩個子任務之間的 切換也就是上下文切換。
建立Greenlets,gevent對Greenlet初始化提供了一些封裝.
第一個
import gevent
def test1():
print 12
gevent.sleep(0)
print 34
def test2():
print 56
gevent.sleep(0)
print 78
gevent.joinall([
gevent.spawn(test1),
gevent.spawn(test2),
])
$ python gevent2.py
12
56
34
78
第二個
import gevent
from gevent import Greenlet
def foo(message, n):
gevent.sleep(n)
print(message)
thread1 = Greenlet.spawn(foo, "Hello", 1)
thread2 = gevent.spawn(foo, "I live!", 2)
thread3 = gevent.spawn(lambda x: (x+1), 2)
threads = [thread1, thread2, thread3]
gevent.joinall(threads)
第二個
$ python gevent3.py
Hello
I live!
import gevent
import random
def task(pid):
gevent.sleep(random.randint(0,2)*0.001)
print('Task %s done' % pid)
def synchronous():
for i in xrange(5):
task(i)
def asynchronous():
threads = [gevent.spawn(task, i) for i in xrange(5)]
gevent.joinall(threads)
print('Synchronous:')
synchronous()
print('Asynchronous:')
asynchronous()
$ python gevent3.py
Synchronous:
Task 0 done
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Asynchronous:
Task 2 done
Task 0 done
Task 1 done
Task 3 done
Task 4 done
參考連線:
https://www.cnblogs.com/machangwei-8/p/10907572.html
https://softlns.github.io/2015/11/28/python-gevent/