A coroutine is a function that can suspend its execution (yield) until the given YieldInstruction finishes.算法
也就是說,協程是一個函數,能夠被掛起和被恢復。編程
協程不是被操做系統內核所管理,而徹底是由程序所控制(也就是在用戶態執行)。這樣帶來的好處就是性能獲得了很大的提高,不會像線程那樣須要上下文切換來消耗資源,所以協程的開銷遠遠小於線程的開銷。多線程
子程序,就是函數,在全部語言中都是層級調用,好比A調用B,B在執行過程當中又調用了C,C執行完畢返回,B執行完畢返回,最後是A執行完畢。函數
協程看上去也是子程序,但執行過程當中,在子程序內部可中斷,而後轉而執行別的子程序,在適當的時候再返回來接着執行。oop
注意,在一個子程序中中斷,去執行其餘子程序,不是函數調用,有點相似CPU的中斷。好比子程序A、B:post
def A(): print '1' print '2' print '3' def B(): print 'x' print 'y' print 'z'
假設由協程執行,在執行A的過程當中,能夠隨時中斷,去執行B,B也可能在執行過程當中中斷再去執行A,結果多是:性能
1 2 x y 3 z
可是在A中是沒有調用B的,因此協程的調用比函數調用理解起來要難一些。spa
看起來A、B的執行有點像多線程,但協程的特色在因而一個線程執行,那操作系統
和多線程比,協程有何優點?線程
1. 切換開銷小,執行效率高
由於子程序切換不是線程切換,而是由程序自身控制
2. 不須要多線程的鎖機制
由於只有一個線程,也不存在同時寫變量衝突,在協程中控制共享資源不加鎖,只須要判斷狀態就行了
協程能夠經過yield(取其「讓步」之義而非「出產」)來調用其它協程,接下來的每次協程被調用時,從協程上次yield返回的位置接着執行,經過yield方式轉移執行權的協程之間不是調用者與被調用者的關係,而是彼此對稱、平等的
1. 子程序能夠調用其餘子程序,調用者等待被調用者結束後繼續執行,故而子程序的生命期遵循後進先出,即最後一個被調用的子例程最早結束返回。協程的生命期徹底由對它們的使用須要來決定。(也就是想怎麼跳就怎麼跳,不須要遵循函數調用那套規則)
2. 子程序的起始處是唯一的入口點,而協程能夠有多個入口點,協程的起始處是第一個入口點,每一個yield返回出口點都是再次被調用執行時的入口點。
3. 子例程只在結束時一次性的返回所有結果值。協程能夠在yield時不調用其餘協程,而是每次返回一部分的結果值,這種協程常稱爲生成器或迭代器。
子例程是協程的特里,由於任何子例程均可以看做是不調用yield的協程
這裏是一個簡單的例子證實協程的實用性。
傳統的生產者-消費者模型是一個線程寫消息,一個線程取消息,經過鎖機制控制隊列和等待,但一不當心就可能死鎖。
若是改用協程,生產者生產消息後,直接經過yield跳轉到消費者開始執行,待消費者執行完畢後,切換回生產者繼續生產,效率極高:
var q := 新建隊列 coroutine 生產者 loop while q 不滿載 創建某些新產品 向 q 增長這些產品 yield 給消費者 coroutine 消費者 loop while q 不空載 從 q 移除某些產品 使用這些產品 yield 給生產者
根據今天查閱的資料來看,協程的應用場景主要在於 :I/O 密集型任務。