goroutine是很是輕量的,不會暫用太多資源,基本上有多少任務,咱們能夠開多少goroutine去處理。但有時候,咱們仍是想控制一下。golang
好比,咱們有A、B兩類工做,不想把太多資源花費在B類務上,而是花在A類任務上。對於A,咱們能夠來1個開一個goroutine去處理,對於B,咱們可使用一個協程池,協程池裏有5個線程去處理B類任務,這樣B消耗的資源就不會太多。緩存
控制使用資源並非協程池目的,使用協程池是爲了更好併發、程序魯棒性、容錯性等。廢話少說,快速入門協程池纔是這篇文章的目的。bash
協程池指的是預先分配固定數量的goroutine處理相同的任務,和線程池是相似的,不一樣點是協程池中處理任務的是協程,線程池中處理任務的是線程。併發
上面這個圖展現了最簡單的協程池的樣子。先把協程池做爲一個總體看,它使用2個通道,左邊的jobCh
是任務通道,任務會從這個通道中流進來,右邊的retCh
是結果通道,協程池處理任務後獲得的結果會寫入這個通道。至於協程池中,有多少協程處理任務,這是外部不關心的。less
看一下協程池內部,圖中畫了5個goroutine,實際goroutine的數量是依具體狀況而定的。協程池內每一個協程都從jobCh
讀任務、處理任務,而後將結果寫入到retCh
。spa
模型看懂了,看個小例子吧。線程
workerPool()
會建立1個簡單的協程池,協程的數量能夠通入參數n
執行,而且還指定了jobCh
和retCh
兩個參數。code
worker()
是協程池中的協程,入參分佈是它的ID、job通道和結果通道。使用for-range
從jobCh
讀取任務,直到jobCh
關閉,而後一個最簡單的任務:生成1個字符串,證實本身處理了某個任務,並把字符串做爲結果寫入retCh
。協程
main()
啓動genJob
獲取存聽任務的通道jobCh
,而後建立retCh
,它的緩存空間是200,並使用workerPool
啓動一個有5個協程的協程池。1s以後,關閉retCh
,而後開始從retCh
中讀取協程池處理結果,並打印。隊列
genJob
啓動一個協程,並生產n個任務,寫入到jobCh
。
示例運行結果以下,一共產生了10個任務,顯示大部分工做都被worker 2
這個協程搶走了,若是咱們設置的任務成千上萬,協程池長時間處理任務,每一個協程處理的工做數量就會均衡不少。
➜ go run simple_goroutine_pool.go worker 2 processed job: 4 worker 2 processed job: 5 worker 2 processed job: 6 worker 2 processed job: 7 worker 2 processed job: 8 worker 2 processed job: 9 worker 0 processed job: 1 worker 3 processed job: 2 worker 4 processed job: 3 worker 1 processed job: 0
最簡單的協程池模型就這麼簡單,再回頭看下協程池及周邊由哪些組成:
jobCh
,存在協程池不能當即處理任務的狀況,因此須要隊列把任務先暫存。retCh
,同上,協程池處理任務的結果,也存在不能被下游馬上提取的狀況,要暫時保存。協程池最簡要(核心)的邏輯是全部協程從任務讀取任務,處理後把結果存放到結果隊列。
- 若是這篇文章對你有幫助,請點個贊/喜歡,鼓勵我持續分享,感謝。
- 若是喜歡本文,隨意轉載,但請保留此原文連接。
- 博客文章列表,點此可查看