GoLang channel使用介紹
停止信號
channel 用于停止信號的場景還是挺多的,經(jīng)常是關閉某個 channel 或者向 channel 發(fā)送一個元素,使得接收 channel 的那一方獲知道此信息,進而做一些其他的操作。
任務定時
與 timer 結合,一般有兩種玩法:實現(xiàn)超時控制,實現(xiàn)定期執(zhí)行某個任務。
有時候,需要執(zhí)行某項操作,但又不想它耗費太長時間,上一個定時器就可以搞定:
select {
case <-time.After(100 * time.Millisecond):
case <-s.stopc:
return false
}
等待 100 ms 后,如果 s.stopc 還沒有讀出數(shù)據(jù)或者被關閉,就直接結束。這是來自 etcd 源碼里的一個例子,這樣的寫法隨處可見。
定時執(zhí)行某個任務,也比較簡單:
func worker() {
ticker := time.Tick(1 * time.Second)
for {
select {
case <- ticker:
// 執(zhí)行定時任務
fmt.Println("執(zhí)行 1s 定時任務")
}
}
}
每隔 1 秒種,執(zhí)行一次定時任務。
解耦生產(chǎn)方和消費方
服務啟動時,啟動 n 個 worker,作為工作協(xié)程池,這些協(xié)程工作在一個 for {} 無限循環(huán)里,從某個 channel 消費工作任務并執(zhí)行:
func main() {
taskCh := make(chan int, 100)
go worker(taskCh)
// 塞任務
for i := 0; i < 10; i++ {
taskCh <- i
}
// 等待 1 小時
select {
case <-time.After(time.Hour):
}
}
func worker(taskCh <-chan int) {
const N = 5
// 啟動 5 個工作協(xié)程
for i := 0; i < N; i++ {
go func(id int) {
for {
task := <- taskCh
fmt.Printf("finish task: %d by worker %d\n", task, id)
time.Sleep(time.Second)
}
}(i)
}
}5 個工作協(xié)程在不斷地從工作隊列里取任務,生產(chǎn)方只管往 channel 發(fā)送任務即可,解耦生產(chǎn)方和消費方。
finish task: 1 by worker 4
finish task: 2 by worker 2
finish task: 4 by worker 3
finish task: 3 by worker 1
finish task: 0 by worker 0
finish task: 6 by worker 0
finish task: 8 by worker 3
finish task: 9 by worker 1
finish task: 7 by worker 4
finish task: 5 by worker 2
控制并發(fā)數(shù)
有時需要定時執(zhí)行幾百個任務,例如每天定時按城市來執(zhí)行一些離線計算的任務。但是并發(fā)數(shù)又不能太高,因為任務執(zhí)行過程依賴第三方的一些資源,對請求的速率有限制。這時就可以通過 channel 來控制并發(fā)數(shù)。
下面的例子來自《Go 語言高級編程》:
var limit = make(chan int, 3)
func main() {
// …………
for _, w := range work {
go func() {
limit <- 1
w()
<-limit
}()
}
// …………
}構建一個緩沖型的 channel,容量為 3。接著遍歷任務列表,每個任務啟動一個 goroutine 去完成。真正執(zhí)行任務,訪問第三方的動作在 w() 中完成,在執(zhí)行 w() 之前,先要從 limit 中拿“許可證”,拿到許可證之后,才能執(zhí)行 w(),并且在執(zhí)行完任務,要將“許可證”歸還。這樣就可以控制同時運行的 goroutine 數(shù)。
這里,limit <- 1 放在 func 內部而不是外部,原因是:
如果在外層,就是控制系統(tǒng) goroutine 的數(shù)量,可能會阻塞 for 循環(huán),影響業(yè)務邏輯。
limit 其實和邏輯無關,只是性能調優(yōu),放在內層和外層的語義不太一樣。
還有一點要注意的是,如果 w() 發(fā)生 panic,那“許可證”可能就還不回去了,因此需要使用 defer 來保證。
到此這篇關于GoLang channel使用介紹的文章就介紹到這了,更多相關Go channel內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決golang編譯提示dial tcp 172.217.160.113:443: con
這篇文章主要介紹了解決golang編譯提示dial tcp 172.217.160.113:443: connectex: A connection attempt failed,此問題完美解決,需要的朋友可以參考下2023-02-02

