fasthttp 的 goroutine pool 實現探究

legendtkl發表於2016-09-20

引言

fasthttp是一個非常優秀的web server框架,號稱比官方的net/http快10倍以上。fasthttp用了很多黑魔法。俗話說,原始碼面前,了無祕密,我們今天通過原始碼來看一看她的goroutine pool的實現。

熱身

fasthttp寫server和原生的net/http寫法上基本沒有區別,這裡就不舉例子。直接找到入口函式,在根目錄下的server.go檔案中,我們從函式ListenAndServe()跟蹤進去。從埠監聽到處理請求的函式呼叫鏈如下。

上面程式碼中workerPool就是一個執行緒池。相關程式碼在server.go檔案的同級目錄下的workerpool.go檔案中。我們從上面程式碼涉及到的往下看。首先是workerPool struct

workerPool sturct中的WorkerFunc是conn的處理函式,類似net/http包中的ServeHTTP。因為所有conn的處理都是一樣的,所以WorkerFunc不需要和傳入的每個conn繫結,整個worker pool共用一個。workerChanPool是sync.Pool物件池。

MaxIdleWorkerDuration是worker空閒的最長時間,超過就將worker關閉。workersCount是worker的數量。ready是可用的worker列表,也就是說所有goroutine worker是存放在一個陣列裡面的。這個陣列模擬一個類似棧的FILO佇列,也就是說我們每次使用的worker都從佇列的尾部開始取。wp.Start()啟動worker pool。wp.Stop()是出錯處理。wp.Serve(c)是對conn進行處理的函式。我們先看一下wp.Start()

簡單來說,wp.Start()啟動了一個goroutine,負責定期清理worker pool中過期worker(過期=未使用時間超過MaxIdleWorkerDuration)。清理操作都在wp.clean()函式中完成,這裡就不繼續往下看了。stopCh是一個標示worker pool停止的chan。上面的for-select-stop是很常用的方式。wp.Stop()負責停止worker pool的處理工作,包括關閉stopCh,清理閒置的worker列表(這時候還有一部分worker在處理conn,待其處理完成通過判斷wp.mustStop來停止)。這裡需要注意的一點是做資源清理的時候,對於channel需要置nil。下面看看最重要的函式wp.Serve()

核心

下面是wp.Serve()函式的呼叫鏈。wp.Serve()負責處理來自client的每一條連線。其中比較關鍵的函式是wp.getCh(),她從worker pool的可用空閒worker列表尾部取出一個可用的worker。這裡有幾個邏輯需要注意的是:1.如果沒有可用的worker(比如處理第一個conn是,worker pool還是空的)則新建;2.如果worker達到上限,則直接不處理(這個地方感覺略粗糙啊!)。go func()那幾行程式碼就是新建worker,我們放到下面說。

workerFunc()函式定義如下(去掉了很多不影響主線的邏輯),結合上一篇《如何裸寫一個goroutine pool》,還是熟悉的配方,熟悉的味道。這裡要看的wp.release()是幹啥的。因為前面的wp.Serve()函式只處理一個conn,所以for迴圈執行一次我們就可以把worker放到空閒佇列中去等待下一次conn過來,從程式碼中可以看出來放回果然是放到空閒佇列的末尾(可算和上面呼應上了)。還有上面提到的mustStop,如果worker pool停止了,mustStop就為true,那麼workerFunc就要跳出迴圈,也就是goroutine結束了。

總結

除了fasthttp,我還看了github上其他開源且star數在100以上的goroutine pool的實現,基本核心原理都在我上一篇文章中說的那些。fasthttp的實現多了一層goroutine回收機制,不得不說確實挺巧妙。fasthttp效能這麼好一定是有其原因的,原始碼之後再慢慢讀。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

fasthttp 的 goroutine pool 實現探究 fasthttp 的 goroutine pool 實現探究

相關文章