什麼是協程
協程(coroutine)的概念根據Donald Knuth的說法早在1958年就由Melvin Conway提出了,對應wikipedia的定義如下:
Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing execution to be suspended and resumed. Coroutines are well-suited for implementing familiar program components such as cooperative tasks, exceptions, event loops, iterators, infinite lists and pipes.
這裡子例程(subroutine)是一個概括性的術語,子例程可以是整個程序中的一個代碼區塊,當它被主程序調用的時候就會進入運行。例如函數就是子例程中的一種。
從wikipedia定義可以看出協程相比子例程更加的靈活,允許執行過程中被掛起和恢復,多個協程可以一起相互協作執行任務。從協程(co + routine)名字上來拆解為支持協作(cooperate)的例程。
協程與子例程的執行區別
圖中左邊是子例程的執行過程,右邊是協程的執行過程,可以很明顯的看出來執行過程中的區別。
先說左邊,子例程可以看成是某個函數,子例程的執行過程中通常是嵌套順序執行的過程,子例程1和子例程2的關係(調用和被調用)不是完全平等的,子例程1能調用子例程2,但子例程2不能反過來調用子例程1。再說右邊,協程1和協程2的關係是完全對等的,協程1執行過程中可以中斷掛起執行另外一個協程2,反之也是可以的,直到最終兩個協程都執行完以後再返回回到主程序中,即協程1和協程2相互協作完成了整個任務。接下來舉一個協程實現生產者和消費者的例子:
這裡有一個隊列queue,一個生產者produce,一個消費者consume,yield代表中斷掛起當前協程,並恢復其他協程的操作。生產者生產物品以後加入到隊列以後,中斷掛起自身並恢復消費者,消費者從隊列中消費完物品以後中斷掛起自身並恢復生產者,不斷來回切換直到達到最終條件(比如所有原料都生產成物品並全都被消費完成),程序終止。
進程、線程、協程的關係和比較
通常會提到進程是資源分配的最小單位,線程是CPU調度的最小單位, 一個進程裡可以有多個線程,這裡直接畫了個圖來說明三者關係。
coroutine的python實現
Python最初的版本里是包含了yield/send關鍵字,通過yield/send可以方便的實現一個協程的例子,這裡還是以為生產者和消費者為例,具體實現方式如下:
結果:
python 3.5版本開始引入了async/await關鍵字給了我們另外一種實現的方法,還是以為生產者和消費者為例,具體實現方式如下:
結果: