Go游戏服务器开发的一些思考(十):goroutine和coroutine
概要
go語言的特色之一就是goroutine。也就是go協程。由于協程這個東西在go語言之前,用到相對比較少,大家對協程的理解程度不一,或有偏差。比如本人剛接觸goroutine時,就對其比較畏懼,因為不知道它到底是如何運作的。因此有必要深入了解下什么是協程,它的今生前世,以及工作原理
前世
作為服務器端程序員,一般來說,都會使用過、或者自己實現過 “通用的異步任務系統” ,來達成安全方便的多線程使用。通常來講,比較典型的會是基于actor模型及回調的方式制定差異。
這里我們主要來考察下其不足之處。下面簡單的畫一下 任務對象和線程間的關系:
------- ------- -------| task1 | | task2 | .... | taskn | => thread1------- ------- -------------- ------- -------| taska | | taskb | .... | taskz | => thread2------- ------- -------...------- ------- -------| taskA | | taskB | .... | taskZ | => threadn------- ------- -------- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
如圖所示,一般會開n個線程來處理,每個任務按一定的策略被投遞到線程中執行,任務完成后,觸發異步回調。
假設 任務中,有一定比例的任務是IO阻礙的。那么線程在執行這個任務時,會被掛起。導致后面的任務也只能等待。
總結下其不足的地方:
* CPU能力不能達到完全釋放* IO阻塞任務的數量與線程被系統調度成正比* 任務完成需要回調方式,編程上不直觀、比較難受(若沒有前兩條不足,這個大概也不會出現。背鍋俠是也...)(ps. 協程起源于單CPU單線程時代。要解決的問題,同這里表述的。多線程后,為了榨干CPU處理能力,協程開始用于多線程系統,如這里描述的)
程序員的智慧
那么如何才能把 “異步任務系統” 做的完美呢。假設能這樣就好了:
* IO阻塞任務,執行到阻塞語句時,系統可以下達它的IO指令又可以把它拎出來,重新插到任務隊列最后。假設能實現這樣的效果。那么上述的不足也就不存在了:
* 阻塞的任務因為拎出來了,后續的任務可以繼續歡快的在該線程上跑了 * 阻塞的任務因為拎出來了,線程也不會被阻塞,也就不會被系統調度出去了那么如何才能做到。聰明的程序員很快找到了解決方案:
* 將IO阻塞的API hook掉,換成異步實現
* 模仿操作系統線程的調度方法,實現任務的切出切進
這里點下,為什么需要 “實現任務的切出切進”。由于把IO阻塞的API hook掉,換成異步實現。如果讓該任務繼續執行的話,就會改變該任務的流程。因此必須切出去。等再次切進來時,檢查IO事件是否已經到了。到了則如同 IO阻塞完畢,繼續執行任務流程。否則再次切出。
今生
于是很多產品出來了。
首先是操作系統,推出了用戶態 上下文切換API
| window | 纖程(Fiber系列API) |
| linux | ucontext系列API |
| 其他 | 大廠直接自己匯編搞定,高級定制(比如go …) |
然后 很多開源庫。這里介紹幾個有名的
| boost | boost::context、boost::coroutine。僅跨平臺提供協程基礎功能。 |
| libco | 騰訊的協程庫。明顯的閹割版放出。沒有提供上層封裝使用層代碼 |
| libgo | 魅族的協程庫。和goroutine使用功能上無限接近。 |
| libtask | goroutine前身。goroutine一出,大家驚呆了,原來封裝的好,也可以這么好用。 |
順便吐槽下,翻下libco、libgo、libtask,會發現代碼中只有task。而到了市面上則變成了 協程(coroutine)。玩起概念來…
goroutine、libgo、libco 比較
| goroutine | 全部hook | 8K開始,動態增加,分段棧實現 | 100% | go代碼太龐大,還沒找到… |
| libco | socket系列API | 可制定大小,共享棧實現 | 最基本的協程功能 | 代碼量小,比較難看,沒看 |
| libgo | socket系列API | 可制定大小,沒有特殊實現 | 接近100% | 代碼量小,可讀性很高,基本看懂 |
(ps.據libgo的作者說,libgo協程棧用了 “os的虛擬內存機制,是動態增長的”。待考究優略 )
C++框架新的可能
C++ libgo庫設計的非常棒,還原 goroutine 程度 接近100%(當然這里指的是用法。穩定性、可靠性還需很多人、產品的檢驗)。因此讓C++引擎具備實用的cocoutine系統已經是完全可行。
總結
以上是生活随笔為你收集整理的Go游戏服务器开发的一些思考(十):goroutine和coroutine的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: golang基础-chan的select
- 下一篇: Go游戏服务器开发的一些思考(九):Do