協程,又稱微線程,纖程。英文名Coroutine。一句話說明什麼是線程:協程是一種用戶態的輕量級線程。python
協程擁有本身的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其餘地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。所以:編程
協程能保留上一次調用時的狀態(即全部局部狀態的一個特定組合),每次過程重入時,就至關於進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。併發
咱們給協程一個標準定義,即符合什麼條件就能稱之爲協程:異步
協程的好處:socket
缺點:異步編程
舉一個栗子:高併發
def consumer(name): print("\033[33;1m[%s]\033[0m 開始吃蛋糕....." %name) while True: dangao = yield print("\033[35;1m[%s]\033[0m 吃了蛋糕 %s" %(name,dangao)) def producer(name): c1.__next__()#啓動生成器 c2.__next__() n = 0 while n < 5: n+=1 print("\033[32;1m[%s]\033[0m 開始製做蛋糕 %s......" %(name,n)) c1.send(n) c2.send(n) if __name__ == "__main__": c1 = consumer("mogu") c2 = consumer("wanzi") p1 = producer("HC")
上面的例子使用yield,完成了一個貌似是協程的生產者消費者模型,可是若是在生產者或者消費者中添加例如sleep之類的操做,這個程序就會變得很慢,與咱們但願出現阻塞操做就切換還差了一些atom
python中有一個模塊叫作greenlet,這個模塊能夠作到出現阻塞就切換到別的操做,也能夠切換回來spa
看下面的栗子:操作系統
from greenlet import greenlet import time def wanzi(): print("wanzi 正在吃蛋糕,看看mogu在幹什麼") gr2.switch() time.sleep(2) print("wanzi 還在吃蛋糕,看看mogu在幹什麼") gr2.switch() def mogu(): print("mogu 正在舔爪子,看看wanzi在幹什麼") gr1.switch() print("mogu 正在打滾。") gr1.switch() gr1 = greenlet(wanzi) gr2 = greenlet(mogu) gr1.switch()
使用greenlet實現了切換的操做,可是阻塞仍是沒有解決
Gevent 是一個第三方庫,能夠輕鬆經過gevent實現併發同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴展模塊形式接入Python的輕量級協程。 Greenlet所有運行在主程序操做系統進程的內部,但它們被協做式地調度。
栗子:
import gevent import time def wanzi(): print("wanzi 正在玩玩具.....看看mogu在幹什麼....") gevent.sleep(10) print("wanzi 看着mogu滿屋跑,哈哈大笑") def mogu(): print("mogu正在舔爪子,看看HC在幹什麼....") gevent.sleep(2) print("mogu添完爪子,正在滿屋亂跑...") def HC(): print("HC 正在給wanzi準備吃的...看看wanzi在幹什麼") gevent.sleep(1) print("HC 正在給wanzi準備吃的...看看wanzi在幹什麼") gevent.sleep(1) print("HC 正在給wanzi準備吃的...看看wanzi在幹什麼") gevent.sleep(1) print("HC 正在給wanzi準備吃的...看看wanzi在幹什麼") gevent.sleep(1) print("HC 正在給wanzi準備吃的...看看wanzi在幹什麼") gevent.sleep(1) print("HC 正在給wanzi準備吃的...看看wanzi在幹什麼") gevent.sleep(1) print("HC 準備喂wanzi吃飯") start_time = time.time() gevent.joinall([ gevent.spawn(wanzi), gevent.spawn(mogu), gevent.spawn(HC) ]) stop_time = time.time() print("cost : %s" %(stop_time-start_time))
使用gevent實現了遇到阻塞(I/O)就自動切換的功能
下面是一組使用協程實現socket大併發的例子
server