日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

grpool?goroutine池協程管理_Golang

作者:??王中陽Go???? ? 更新時間: 2022-08-01 編程語言

前言

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

欄目分類
最近更新