ゴーファーの皆さん! ?今日は、古典的な「ゴルーチンが多すぎる」という悩みからあなたを救うかもしれないもの、GoFrame の grpool について詳しく見ていきましょう。 Go で同時実行性の高いサービスを扱ったことがある人なら、その手順をご存知でしょう。ゴルーチンを生成し、管理し、生成しすぎないように祈ります...しかし、もっと良い方法があったとしたらどうでしょうか?
これを想像してみてください。アップロードの処理、API からのデータの取得、WebSocket 接続の処理など、複数の同時タスクを処理する必要があるサービスを構築しています。あなたの最初の直感は次のとおりかもしれません:
for task := range tasks { go processTask(task) // Look ma, concurrency! }
十分無邪気そうに見えますよね?しかし、運用環境では、何千ものリクエストがあるため、次のような結果になる可能性があります。
ここで grpool が役に立ちます! ?♂️
grpool は GoFrame フレームワークの一部ですが、ここが優れた点です。独立して使用できるのです。これは、タスクごとに新しいワーカーを雇用 (作成) するのではなく、タスクを引き受ける準備ができているワーカー (ゴルーチン) のチームを用意するようなものです。
まず、パッケージを取得します:
go get github.com/gogf/gf/v2
これを使用する最も簡単な方法は次のとおりです:
import "github.com/gogf/gf/v2/os/grpool" func main() { ctx := context.Background() // Create a pool with 10 workers pool := grpool.New(10) // Add a task - it's this simple! pool.Add(ctx, func(ctx context.Context) { fmt.Println("Task executed by a worker from the pool!") }) }
実用的なもの、つまり複数のアップロードを同時に処理できる画像プロセッサを構築してみましょう:
package main import ( "context" "fmt" "github.com/gogf/gf/v2/os/grpool" "sync" ) func processImages() { // Create a pool with 5 workers pool := grpool.New(5) ctx := context.Background() var wg sync.WaitGroup // Simulate 20 image uploads images := make([]string, 20) for i := range images { wg.Add(1) imageURL := fmt.Sprintf("image_%d.jpg", i) pool.Add(ctx, func(ctx context.Context) { defer wg.Done() processImage(imageURL) }) } wg.Wait() } func processImage(url string) { // Simulate image processing fmt.Printf("Processing %s\n", url) // Your actual image processing logic here }
grpool と生の goroutine を比較するベンチマークをいくつか実行しました。私が見つけたものは次のとおりです:
func BenchmarkComparison(b *testing.B) { ctx := context.Background() b.Run("With grpool", func(b *testing.B) { pool := grpool.New(10) for i := 0; i < b.N; i++ { pool.Add(ctx, func(ctx context.Context) { time.Sleep(time.Millisecond) }) } }) b.Run("Without pool", func(b *testing.B) { for i := 0; i < b.N; i++ { go func() { time.Sleep(time.Millisecond) }() } }) }
私のマシンでの結果:
BenchmarkComparison/With_grpool-8 5804 202395 ns/op BenchmarkComparison/Without_pool-8 3662 304738 ns/op
これは、パフォーマンスが約 33% 向上したことになります。 ?
// For CPU-bound tasks pool := grpool.New(runtime.NumCPU()) // For I/O-bound tasks pool := grpool.New(runtime.NumCPU() * 2)
pool.Add(ctx, func(ctx context.Context) { defer func() { if err := recover(); err != nil { log.Printf("Task panicked: %v", err) } }() // Your task code here })
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() pool.Add(ctx, func(ctx context.Context) { select { case <-ctx.Done(): fmt.Println("Task cancelled!") return default: // Your task code here } })
grpool は次の場合に輝きます:
grpool は、「なぜ今までこれを使わなかったの?」と思わせるツールの 1 つです。シンプルなのですぐに使い始めることができますが、運用環境での使用には十分強力です。次のプロジェクトで試してみて、どうなるか教えてください!
grpool または同様の goroutine プール実装を使用したことがありますか?以下のコメント欄であなたの経験を共有してください! ?
注: 上記のベンチマークはローカル マシンで実行されました。結果はハードウェアとワークロードによって異なる場合があります。
以上がGoFrame の grpool で Go の同時タスクを大幅に強化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。