Go で同時 HTTP リクエストを最大化する方法
多くのプログラミング言語とフレームワークは、HTTP リクエストを作成するためのツールを提供していますが、多数のリクエストを同時に処理する場合、同時実行性を最大化してパフォーマンスを最適化する方法を理解することが不可欠です。この記事では、ゴルーチンを利用してシステムの処理能力の可能性を最大限に引き出し、Go で同時 HTTP リクエストを「最大化」する複雑さを詳しく掘り下げます。
問題:
複数のメソッドを使用して、特定の URL への 100 万件の HTTP リクエストをできるだけ早く生成するシナリオを考えてみましょう。ゴルーチン。ただし、最初の投稿で提供されたコードでは、ファイル記述子の制限を超えたためエラーが発生しました。これは、多数の同時リクエストを処理しようとするときによくある問題です。
解決策:
同時実行性を効果的に最大化するには、次の方法でファイル記述子の制限に対処できます。ワーカー プール モデル内のセマフォ メカニズムとしてバッファー チャネルを採用します。ソリューションの内訳は次のとおりです:
ワーカー プール:
セマフォ チャネル:
ディスパッチャー:
コンシューマ:
最適化されたコード:
package main import ( "flag" "fmt" "log" "net/http" "runtime" "time" ) var ( reqs int max int ) func init() { flag.IntVar(&reqs, "reqs", 1000000, "Total requests") flag.IntVar(&max, "concurrent", 200, "Maximum concurrent requests") } type Response struct { *http.Response err error } // Dispatcher func dispatcher(reqChan chan *http.Request) { defer close(reqChan) for i := 0; i < reqs; i++ { req, err := http.NewRequest("GET", "http://localhost/", nil) if err != nil { log.Println(err) } reqChan <- req } } // Worker Pool func workerPool(reqChan chan *http.Request, respChan chan Response) { t := &http.Transport{} for i := 0; i < max; i++ { go worker(t, reqChan, respChan) } } // Worker func worker(t *http.Transport, reqChan chan *http.Request, respChan chan Response) { for req := range reqChan { resp, err := t.RoundTrip(req) r := Response{resp, err} respChan <- r } } // Consumer func consumer(respChan chan Response) (int64, int64) { var ( conns int64 size int64 ) for conns < int64(reqs) { select { case r, ok := <-respChan: if ok { if r.err != nil { log.Println(r.err) } else { size += r.ContentLength if err := r.Body.Close(); err != nil { log.Println(r.err) } } conns++ } } } return conns, size } func main() { flag.Parse() runtime.GOMAXPROCS(runtime.NumCPU()) reqChan := make(chan *http.Request) respChan := make(chan Response) start := time.Now() go dispatcher(reqChan) go workerPool(reqChan, respChan) conns, size := consumer(respChan) took := time.Since(start) ns := took.Nanoseconds() av := ns / conns average, err := time.ParseDuration(fmt.Sprintf("%d", av) + "ns") if err != nil { log.Println(err) } fmt.Printf("Connections:\t%d\nConcurrent:\t%d\nTotal size:\t%d bytes\nTotal time:\t%s\nAverage time:\t%s\n", conns, max, size, took, average) }
この改良されたコードは、前に説明した要素を組み合わせて、大量の HTTP リクエストを同時に送信するための、非常に効率的なワーカー プール ベースのシステムを作成します。セマフォ チャネルを通じて同時リクエストの数を慎重に制御することで、ファイル記述子の制限に関連する問題を回避し、システムのリソースを最大限に活用できます。
要約すると、ゴルーチン、セマフォ チャネル、ワーカー プール、および応答を処理する専用コンシューマを利用することで、Go での同時 HTTP リクエストを効果的に「最大化」できます。このアプローチにより、パフォーマンス テストとストレス テストを効果的に実施し、システムを限界まで引き上げ、その機能についての貴重な洞察を得ることができます。
以上がGoルーチンとワーカープールを使用してGoで同時HTTPリクエストを最大化する方法?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。