網站首頁 編程語言 正文
前言
goroutine協程非常輕量級,這也是為什么go支持高并發,但是goroutine頻繁創建銷毀對GC的壓力比較大。
grpool的作用就是復用goroutine,減少頻繁創建銷毀的性能消耗。
名詞概念
Pool: goroutine池,用于管理若干可復用的goroutine協程資源
Worker: 池對象中參與任務執行的goroutine,一個worker可以執行若干個job,直到隊列中再無等待的job
Job:添加到池對象的任務隊列中等待執行的任務,是一個func()方法,一個job同時只能被一個worker獲取并執行。
使用示例
使用默認的協程池,限制100個協程執行1000個任務
pool.Size() 獲得當前工作的協程數量
pool.Jobs() 獲得當前池中待處理的任務數量
package main import ( "fmt" "github.com/gogf/gf/os/grpool" "github.com/gogf/gf/os/gtimer" "sync" "time" ) func main() { pool := grpool.New(100) //添加1千個任務 for i := 0; i < 1000; i++ { _ = pool.Add(job) } fmt.Println("worker:", pool.Size()) //當前工作的協程數量 fmt.Println("jobs:", pool.Jobs()) //當前池中待處理的任務數量 gtimer.SetInterval(time.Second, func() { fmt.Println("worker:", pool.Size()) //當前工作的協程數 fmt.Println("jobs:", pool.Jobs()) //當前池中待處理的任務數 }) //阻止進程結束 select {} } //任務方法 func job() { time.Sleep(time.Second) }
打印結果:
是不是灰常簡單~
踩坑之旅
一個簡單的場景,請使用協程打印0~9。
常犯的錯誤
大家看下面的代碼有沒有問題,請預測一下打印結果。
wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) go func() { fmt.Println(i) wg.Done() }() } wg.Wait()
不用著急看答案
猜一下打印結果是什么
打印結果:
分析原因
對于異步線程/協程來講,函數進行異步執行注冊時,該函數并未真正開始執行(注冊時只在goroutine
的棧中保存了變量i
的內存地址),而一旦開始執行時函數才會去讀取變量i
的值,而這個時候變量i
的值已經自增到了9
。
正確寫法:
wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) go func(v int) { fmt.Println(v) wg.Done() }(i) } wg.Wait()
打印結果:
使用grpool
使用grpool和使用go一樣,都需要把當前變量i的值賦值給一個不會改變的臨時變量,在函數中使用該臨時變量而不是直接使用變量i
。
錯誤代碼
wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) _ = grpool.Add(func() { fmt.Println(i) //打印結果都是9 wg.Done() }) } wg.Wait()
打印結果:
正確代碼
wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) v := i //grpoll.add() 的參數只能是不帶參數的匿名函數 因此只能以設置臨時變量的方式賦值 _ = grpool.Add(func() { fmt.Println(v) wg.Done() }) } wg.Wait()
打印結果:
總結
通過這篇文章我們了解到:grpool的作用就是復用goroutine,減少頻繁創建銷毀的性能消耗。也了解到使用協程容易犯的錯誤,以及用臨時變量的方式來解決問題。
說句題外話:grpool的基礎概念:Pool、Worke、Job 和我之前設計的派單系統簡直一模一樣。
原文鏈接:https://juejin.cn/post/7104661248213516319
相關推薦
- 2023-04-12 C#?DataGridView行列轉換的具體實現_python
- 2023-01-14 Go?庫bytes.Buffer和strings.Builder使用及性能對比_Golang
- 2022-03-24 基于Docker的可持續交付問題_docker
- 2022-09-02 Python常用編碼的區別介紹_python
- 2022-08-17 jQuery實現購物車_jquery
- 2022-07-13 Win系統服務器管理器打開方式
- 2022-04-02 docker建立私有倉庫的過程_docker
- 2022-12-09 C++哈希表之閉散列方法的模擬實現詳解_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同步修改后的遠程分支