grpoolgoroutineプールの詳細な説明|コルーチン管理

創造を続け、成長を加速させましょう!「ナゲッツデイリーニュープラン・6月アップデートチャレンジ」に参加して9日目です。クリックしてイベントの詳細をご覧ください。

序文

ゴルーチンコルーチンは非常に軽量であるため、goは高い同時実行性をサポートしますが、ゴルーチンの頻繁な作成と破棄はGCに大きなプレッシャーをかけます。

grpoolの役割は、頻繁な作成と破棄のパフォーマンス消費を減らすために、ゴルーチンを再利用することです。

名詞の概念

プール:いくつかの再利用可能なコルーチンコルーチンリソースを管理するために使用されるゴルーチンプール

ワーカー:プールオブジェクトのタスク実行に参加しているゴルーチン。キューに待機中のジョブがなくなるまで、ワーカーは複数のジョブを実行できます。

ジョブ:実行を待機しているプールオブジェクトのタスクキューに追加されるタスクは、func()メソッドです。ジョブは、同時に1人のワーカーによってのみ取得および実行できます。

使用例

デフォルトのコルーチンプールを使用して、1000個のタスクを実行する100個のコルーチンを制限します

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)
}
复制代码

結果を印刷

image.png

そんなに簡単じゃないですか〜

ピットへの旅

簡単なシナリオでは、コルーチンを使用して0〜9を印刷してください。

よくある間違い

以下のコードに問題がないか見てみましょう。印刷結果を予測してください。

wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
   wg.Add(1)
   go func() {
      fmt.Println(i)
      wg.Done()
   }()
}
wg.Wait()
复制代码

答えを気にしないでください

印刷結果が何であるかを推測します

結果を印刷

image.png

理由を分析する

非同期スレッド/コルーチンの場合、関数が非同期実行に登録されると、関数は実際には実行を開始せず(登録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()
复制代码

結果を印刷

image.png

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()
复制代码

結果を印刷

image.png

正しいコード

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()
复制代码

結果を印刷

image.png

要約する

この記事を通じて、grpoolの役割は、頻繁な作成と破棄のパフォーマンス消費を減らすためにゴルーチンを再利用することであることを学びました。

また、コルーチンを使用するときに起こりやすい間違いと、一時変数の問題を解決する方法についても学びました。

余談:grpoolの基本概念:Pool、Worke、Jobは、私が以前に設計した注文ディスパッチングシステムとまったく同じです。

やっと

読んでくれてありがとう、そしてみんなを歓迎します:いいね、お気に入り、コイン(焦点を合わせる)!

8e95dac1fd0b2b1ff51c08757667c47a.gif

おすすめ

転載: juejin.im/post/7104661248213516319