Go Channel應(yīng)用系列之控制協(xié)程數(shù)量
大家好,我是漁夫子。
今天給大家介紹一下如何利用go中的緩沖channel來(lái)控制協(xié)程的數(shù)量。如下示例:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
sem := make(chan struct{}, 10)
var count int32
for {
//time.Sleep(5*time.Millisecond)
go func() {
sem <- struct{}{}
atomic.AddInt32(&count, 1)
defer func() {
<-sem
atomic.AddInt32(&count, -1)
}()
fmt.Printf("count is :%d\n", count)
}()
}
}
在這個(gè)示例中,我們首先在for外層初始化了一個(gè)緩沖channel:sem,該channel可以存放10個(gè)元素。在for循環(huán)中我們不停的啟動(dòng)協(xié)程。在協(xié)程中我們嘗試往sem中發(fā)送元素,如果發(fā)送成功,就運(yùn)行后面的邏輯,如果發(fā)送不成功,即sem空間已經(jīng)滿(mǎn)了,就利用channel的堵塞特性,該協(xié)程在這里堵塞等待。最后等某個(gè)協(xié)程運(yùn)行完畢后,從通道sem中輸出一個(gè)元素,這樣就騰出來(lái)一個(gè)空間,讓堵塞的一個(gè)協(xié)程繼續(xù)運(yùn)行了。
這樣,我們?cè)趂or循環(huán)中雖然一直在不停的啟用協(xié)程,但能夠運(yùn)行的協(xié)程數(shù)量不會(huì)超過(guò)10個(gè)。這樣利用了通道的阻塞特定,不用加鎖就能實(shí)現(xiàn)控制協(xié)程數(shù)量的目的。
應(yīng)用示例
在之前我們推薦過(guò)一個(gè)爬蟲(chóng)的開(kāi)源項(xiàng)目:Geziyor。這個(gè)項(xiàng)目中就使用了這種方式來(lái)控制并發(fā)請(qǐng)求的數(shù)量。我們看下源代碼:首先,在初始化的地方,先根據(jù)并發(fā)個(gè)數(shù)來(lái)初始化了一個(gè)緩沖通道,示例代碼看源碼第109行
圖片
然后,在Start函數(shù)中,循環(huán)啟動(dòng)每一個(gè)采集的任務(wù)。源代碼中的106行Start函數(shù),如下:
圖片
然后,在源代碼的第220行,則啟動(dòng)任務(wù)協(xié)程,在任務(wù)協(xié)程中首先通過(guò)acquireSem函數(shù)往通道中發(fā)送一個(gè)消息,如果發(fā)送不成功就堵塞在這里,直到其他協(xié)程通過(guò)releaseSem釋放通道中的一個(gè)空間出來(lái)。如下:
圖片
好了,今天緩沖通道的其中應(yīng)用場(chǎng)景就分享到這里。