說到coroutine就不的不說subroutine,也就是我們常用到的一般函數。調用一個函數開始執行,然後函數執行完成後就退出,再次調用的時候,再從頭開始,調用之間是沒有保存狀態的;但是coroutine是可以在退出時如果再次被調用,可以從上一次退出的點繼續執行。也就是說coroutine的調用之間是會保存狀態的。如果有多個coroutine,就可以反復調用,但是兩個coroutine相互前進。當一個coroutine退出時,不是return,而是yield,表示把當前的執行權交由下一個coroutine處理,或者交出一個結果值。coroutine與我們常用到的thread有點類似,一個thread會執行一個我們指定的函數,然後當該函數調用一個阻塞IO或者同步等待一個事件或者消息時,就會被操作系統調度到等待隊列,當完成或者事件響應後,線程就會繼續從等待的地方執行。thread和coroutine最大的區別就是調度方式的區別,前者一般都是基於時間片的搶占式調度,而coroutine都是協作式調度。
話說回來,我們一般用的函數可以很容易的轉換到coroutine。coroutine中還有一個特例,就是generator. Generator可以像一般的coroutine一樣從上一次返回的地方繼續執行,也可以yield多次,也可以把自己掛起,但是一般的coroutine可以在yield時指定下一個要執行的coroutine,而generator不能這麼做。因此,generator一般用來實現迭代器。
Coroutine可以很方便的用來實現狀態機。 Coroutine實現狀態機會讓代碼變的更可讀。比如實現一個SMTP客戶端,用的是event-driven范式實現,那麼就需要記錄每次處理的狀態,代碼會變得異常復雜。假設你還是使用的event-driven范式實現,但是你用到了coroutine,coroutine內部的流程就是一般SMTP的流程,只是需要每一步請求發送後就退出,然後當收到回應包時event-driven引擎又再次調用了你的coroutine,直接到了上一次退出的地方,是不是感覺更清爽?
因為coroutine比thread相比要輕量的多,thread在操作系統層面實現,調度方式涉及到CPU上下文的切換,和coroutine的協作式調度相比要重了一些,在高並發場景中針對每個請求用thread承載會變的非常低效,但是coroutine反而容易在語言層面或者庫層面實現,因此調度代價要低很多。像Lua的coroutine實現要求程序員自己調用yield自己調度,比較麻煩,但是假設像Golang,Erlang等語言把顯示的協作調度隱藏起來,讓程序員專注功能實現,會更容易讓人接受。在golang中叫coroutine叫goroutine,當goroutine中調用了阻塞操作或者Channel的讀寫操作時,就會導致對應的goroutine得到執行,當完成後又會被調度回來繼續執行,這種同步的編程方式可以讓並發場景進行簡化,讓邏輯變得更清晰。Golang的這種實現把一般的顯示的協作調度隱藏起來,更容易被程序員接受。
一般Coroutine多在帶有GC機制的語言中實現,像在C/C++下實現coroutine會比較復雜和麻煩,不過還是有很多不同的實現,比如Russ Cox實現的libtask庫,C++下的boost.coroutine庫等等。其中我覺著最亮的是 大牛Simon Tatham(putty的作者)基於Duff's Device實現的版本《Coroutine in C》。其中展示了如何把一個復雜的decompressor用coroutine簡化的。Simon大神實現了兩種coroutine,一種是基於static變量保存狀態的,另外一種是通過參數傳遞一個指針的指針保存狀態的。後者更通用一些。詳細代碼點擊這裡。
asio中的coroutine的實現與上面Simon的第一種實現一樣。所以沒有太多可說的。boost.asio.coroutine的使用非常簡單,在自己代碼中包含coroutine.hpp和yield.hpp,創建一個類,派生自coroutine類。然後可以根據自己的業務要求寫相應的coroutine了。當然,也可以把coroutine類作為自己的成員變量組合到自己的類中。
asio的作者也對其做了詳細的說明《A potted guide to stackless coroutines》,同時還寫了專門個使用指南《Composed operations, coroutines and code makeover》。
想用Coroutine建議還是用些現代的新語言吧,比如Golang, Erlang, Scala等。
該可執行程序(executation)的協同程序(coroutine)可以在任何使用yield聲明的地方暫停。yield返回值指定何時coroutine被復用。 當模型構建在多個框架上時Coroutines表現優秀。 Coroutines幾乎沒有任何的性能開銷。 ,不論您能否正確得到結果StartCoroutine功能總是能立即返回。這將等到協同程序(couroutine,我懷疑原文此處有誤,我當做coroutine翻譯了)已完成了可執行程序。
不是太好,我沒接觸過協成的東東。希望能幫到你。
a[n], a = a, a[n]
仔細看這句並行賦值,若 a 是一個表,則賦值結束以後,a 就變成它的元素了(在本例中,也就是一個 number)