--------------
Golang線程池實現百萬級高併發
本文基於Golang實現線程池,從而可以達到百萬級別的高併發請求。本文實現的代碼在https://github.com/lk668/threadpool可見。
1. Golang併發簡介
Golang原生的goroutine可以很輕鬆實現併發編程。Go語言的併發是基於用戶態的併發,這種併發方式就變得非常輕量,能夠輕鬆運行幾萬併發邏輯。Go 的併發屬於 CSP 併發模型的一種實現,CSP 併發模型的核心概念是:不要通過共享內存來通信,而應該通過通信來共享內存。
2. 併發方案演進
2.1 直接使用goroutine
直接使用goroutine啓動一個新的線程來進行任務的執行
1
|
go handler(request)
|
2.2 緩衝隊列
利用channel實現一個緩衝隊列,每次請求先放入緩衝隊列,然後從緩衝隊列讀取數據,一次執行
1
|
type Job interface{
|
該方案在請求量低於緩衝隊列長度時,可以應對併發請求。但是當併發請求量大於緩衝隊列長度時,channel會出現阻塞情況。
2.3 線程池實現百萬級高併發
更好的實現方案是利用job隊列+線程池來實現,具體如下所示:
有個全局JobQueue,用來存儲需要執行的Job,有個WorkerPool的線程池,用來存儲空閒的Worker。當JobQueue中有Job時,從JobQueue獲取Job對象,從WorkerPool獲取空閒Worker,將Job對象發送給Worker,進行執行。每個Worker都是一個獨立的Goroutine。從而真正意義上實現高併發。
代碼實現主要分爲三部分
2.3.1 Job定義
Job是一個interface,其下有個函數RunTask,用戶定製化的任務,需要實現RunTask函數。JobChan是一個Job channel結構。Job是高併發需要執行的任務
1
|
type Job interface {
|
2.3.2 Worker定義
Worker就是高併發裏面的一個線程,啓動的時候是一個Goroutine。Worker結構一需要一個JobChan,用來接收從全局JobQueue裏面獲取的Job對象。有個Quit的channel,用來接收退出信號。需要一個Start函數,將自己註冊到WorkerPool,然後監聽Job,有Job傳入時,處理Job的RunTask,處理完成之後,重新將自己添加回WorkerPool。
1
|
// Worker結構體
|
2.3.3 WorkerPool定義
WorkerPool是一個線程池,用來存儲Worker。所以需要一個Size變量,用來表示這個Pool存儲的Worker的個數。需要一個JobQueue,用來充當全局JobQueue的作用,所有的job先存儲到該全局JobQueue中。有個WorkerQueue是個channel,用來存儲空閒的Worker,有Job來的時候,從WorkerQueue裏面取出一個Worker,執行相應的任務,執行完成以後,重新將Worker放回WorkerQueue。
WorkerPool需要一個啓動函數,一個是來啓動Size數量的Worker線程,一個是需要啓動一個新的線程,來接收Job。
1
|
// 線程池
|
2.3.4 代碼調用舉例
接下來,舉例分析如何使用該線程池。首先需要定義你要執行的任務,實現RunTask函數。然後初始化一個WorkerPool,將模擬百萬請求的數據發送給全局JobQueue。交給線程池進行任務處理。
1
|
//需要執行任務的結構體
|
參考