網站首頁 編程語言 正文
停止信號
channel 用于停止信號的場景還是挺多的,經常是關閉某個 channel 或者向 channel 發送一個元素,使得接收 channel 的那一方獲知道此信息,進而做一些其他的操作。
任務定時
與 timer 結合,一般有兩種玩法:實現超時控制,實現定期執行某個任務。
有時候,需要執行某項操作,但又不想它耗費太長時間,上一個定時器就可以搞定:
select { case <-time.After(100 * time.Millisecond): case <-s.stopc: return false }
等待 100 ms 后,如果 s.stopc 還沒有讀出數據或者被關閉,就直接結束。這是來自 etcd 源碼里的一個例子,這樣的寫法隨處可見。
定時執行某個任務,也比較簡單:
func worker() { ticker := time.Tick(1 * time.Second) for { select { case <- ticker: // 執行定時任務 fmt.Println("執行 1s 定時任務") } } }
每隔 1 秒種,執行一次定時任務。
解耦生產方和消費方
服務啟動時,啟動 n 個 worker,作為工作協程池,這些協程工作在一個 for {}
無限循環里,從某個 channel 消費工作任務并執行:
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 個工作協程 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 個工作協程在不斷地從工作隊列里取任務,生產方只管往 channel 發送任務即可,解耦生產方和消費方。
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
控制并發數
有時需要定時執行幾百個任務,例如每天定時按城市來執行一些離線計算的任務。但是并發數又不能太高,因為任務執行過程依賴第三方的一些資源,對請求的速率有限制。這時就可以通過 channel 來控制并發數。
下面的例子來自《Go 語言高級編程》:
var limit = make(chan int, 3) func main() { // ………… for _, w := range work { go func() { limit <- 1 w() <-limit }() } // ………… }
構建一個緩沖型的 channel,容量為 3。接著遍歷任務列表,每個任務啟動一個 goroutine 去完成。真正執行任務,訪問第三方的動作在 w() 中完成,在執行 w() 之前,先要從 limit 中拿“許可證”,拿到許可證之后,才能執行 w(),并且在執行完任務,要將“許可證”歸還。這樣就可以控制同時運行的 goroutine 數。
這里,limit <- 1
放在 func 內部而不是外部,原因是:
如果在外層,就是控制系統 goroutine 的數量,可能會阻塞 for 循環,影響業務邏輯。
limit 其實和邏輯無關,只是性能調優,放在內層和外層的語義不太一樣。
還有一點要注意的是,如果 w() 發生 panic,那“許可證”可能就還不回去了,因此需要使用 defer 來保證。
原文鏈接:https://blog.csdn.net/qq_53267860/article/details/126918536
相關推薦
- 2022-05-17 基于Pytorch的神經網絡之Regression的實現_python
- 2023-01-29 python?index()?與?rindex()?方法的使用示例詳解_python
- 2022-06-25 iOS自定義滑桿效果_IOS
- 2024-03-13 QAobject修改excel字體亂碼問題
- 2022-11-09 Android?使用maven?publish插件發布產物(aar)流程實踐_Android
- 2022-10-15 Go?Excelize?API源碼閱讀GetPageLayout及SetPageMargins_Go
- 2022-08-18 Android?Canva實現漸變進度條_Android
- 2022-03-12 c++調用實現yolov5轉onnx介紹_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支