Bolehkah Komputer Riba Anda Mengendalikan Sejuta Permintaan HTTP Serentak?
Bayangkan menghantar 1,000,000 permintaan HTTP serentak ke perkhidmatan API REST, menolak had komputer anda untuk memaksimumkan konkurensi. Walaupun alatan wujud untuk tugasan ini, mari kita mendalami cara melakukannya dalam Go menggunakan goroutines.
package main import ( "fmt" "net/http" "runtime" "time" ) func main() { runtime.GOMAXPROCS(runtime.NumCPU()) // Use all available CPU cores transport := &http.Transport{} // Create an HTTP transport for i := 0; i < 1000000; i++ { go func() { // Start a goroutine for each HTTP request req, _ := http.NewRequest("GET", "http://myapi.com", nil) req.Header.Set("User-Agent", "custom-agent") req.SetBasicAuth("xxx", "xxx") resp, err := transport.RoundTrip(req) if err != nil { panic("HTTP request failed.") } defer resp.Body.Close() if resp.StatusCode != 302 { panic("Unexpected response returned.") } location := resp.Header.Get("Location") if location == "" { panic("No location header returned.") } fmt.Println("Location Header Value:", location) }() } time.Sleep(60 * time.Second) // Sleep for 60 seconds }
Tetapi Tunggu, Ada Masalah!
Menjalankan skrip ini mengakibatkan ralat disebabkan oleh had deskriptor fail. Sistem ini tidak boleh mengendalikan begitu banyak sambungan serentak.
Penyelesaian yang Diperbaiki
Untuk mengatasi batasan ini, kita perlu menggunakan pendekatan yang lebih canggih.
Menggunakan Kolam Penghantar dan Pekerja
Ini penyelesaian melibatkan mencipta goroutine penghantar yang menolak permintaan ke saluran. Kumpulan goroutine pekerja menarik permintaan daripada saluran, memprosesnya dan menghantarnya ke saluran respons. Sebuah goroutine pengguna kemudian memproses respons.
// Dispatcher function func dispatcher(reqChan chan *http.Request, reqs int) { 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 function 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 function func consumer(respChan chan Response, reqs int) (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 }
Hasil
Menjalankan skrip yang dipertingkat ini menjana hasil yang mengagumkan, seperti:
Sambungan: 1000000
Serentak: 200
Jumlah saiz: 15000000 bait
Jumlah masa: 38m20.3012317s
Purata masa: 2.280131ms
Mengoptimumkan Prestasi
Walau bagaimanapun, mengubah bilangan permintaan serentak dan jumlah permintaan akan membantu anda had sistem anda dan uji tekanan keupayaannya. Ingat, ini adalah ujian yang melampau dan boleh menggunakan sumber sistem dengan pantas.
Atas ialah kandungan terperinci Bolehkah Komputer Riba Saya Mengendalikan Sejuta Permintaan HTTP Serentak Menggunakan Go?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!