Cara Memaksimumkan Permintaan HTTP Serentak dalam Go
Banyak bahasa pengaturcaraan dan rangka kerja menyediakan alatan untuk membuat permintaan HTTP, tetapi jika anda perlu menghantar sebilangan besar permintaan serentak, adalah penting untuk memahami cara memaksimumkan keselarasan untuk mengoptimumkan prestasi. Artikel ini akan menyelidiki selok-belok "memaksimumkan" permintaan HTTP serentak dalam Go, menggunakan goroutine untuk melancarkan potensi penuh keupayaan pemprosesan sistem anda.
Masalahnya:
Mari kita pertimbangkan senario di mana kita ingin menjana sejuta permintaan HTTP ke URL tertentu secepat mungkin, menggunakan berbilang goroutine. Walau bagaimanapun, kod yang disediakan dalam catatan awal mengakibatkan ralat disebabkan oleh had deskriptor fail yang dilampaui. Ini adalah isu biasa apabila cuba mengendalikan sejumlah besar permintaan serentak.
Penyelesaian:
Untuk memaksimumkan konkurensi secara berkesan, kami boleh menangani had deskriptor fail dengan menggunakan saluran buffer sebagai mekanisme semafor dalam model kumpulan pekerja. Berikut ialah pecahan penyelesaian:
Kolam Pekerja:
Saluran Semaphore:
Penghantar:
Pengguna:
Kod Dioptimumkan:
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) }
Kod yang dipertingkatkan ini menggabungkan elemen yang dibincangkan sebelum ini kepada cipta sistem berasaskan kumpulan pekerja yang sangat cekap untuk menghantar sejumlah besar permintaan HTTP secara serentak. Dengan mengawal bilangan permintaan serentak dengan teliti melalui saluran semaphore, kami boleh mengelakkan sebarang isu yang berkaitan dengan had deskriptor fail dan memaksimumkan penggunaan sumber sistem kami.
Ringkasnya, dengan menggunakan goroutine, saluran semaphore, kumpulan pekerja dan pengguna yang berdedikasi untuk mengendalikan respons, kami boleh "memaksimumkan" permintaan HTTP serentak dalam Go dengan berkesan. Pendekatan ini membolehkan kami menjalankan ujian prestasi dan ujian tekanan dengan berkesan, mendorong sistem kami ke had dan memperoleh cerapan berharga tentang keupayaannya.
Atas ialah kandungan terperinci Bagaimana untuk Memaksimumkan Permintaan HTTP Serentak dalam Go Menggunakan Goroutines dan Worker Pools?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!