Comment maximiser les requêtes HTTP simultanées dans Go
De nombreux langages et frameworks de programmation fournissent des outils pour effectuer des requêtes HTTP, mais si vous devez envoyer un grand nombre de requêtes simultanément, il est essentiel de comprendre comment maximiser la simultanéité pour optimiser les performances. Cet article approfondira les subtilités de la « maximisation » des requêtes HTTP simultanées dans Go, en utilisant des goroutines pour libérer tout le potentiel des capacités de traitement de votre système.
Le problème :
Considérons un scénario dans lequel nous souhaitons générer un million de requêtes HTTP vers une URL spécifique le plus rapidement possible, en utilisant plusieurs goroutines. Cependant, le code fourni dans le message initial a entraîné des erreurs dues au dépassement des limites des descripteurs de fichiers. Il s'agit d'un problème courant lorsque l'on tente de gérer un grand nombre de requêtes simultanées.
La solution :
Pour maximiser efficacement la simultanéité, nous pouvons résoudre la limitation du descripteur de fichier en en utilisant un canal tamponné comme mécanisme de sémaphore dans un modèle de pool de travailleurs. Voici un aperçu de la solution :
Groupe de travailleurs :
Canal Sémaphore :
Répartiteur :
Consommateur :
Code optimisé :
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) }
Ce code amélioré combine les éléments évoqués précédemment pour créer un système basé sur un pool de travailleurs très efficace pour envoyer simultanément un grand volume de requêtes HTTP. En contrôlant soigneusement le nombre de requêtes simultanées via le canal sémaphore, nous pouvons éviter tout problème lié aux limites des descripteurs de fichiers et maximiser l'utilisation des ressources de notre système.
En résumé, en utilisant des goroutines, un canal sémaphore, un pool de travailleurs et un consommateur dédié pour gérer les réponses, nous pouvons efficacement « maximiser » les requêtes HTTP simultanées dans Go. Cette approche nous permet d'effectuer des tests de performance et des tests de résistance de manière efficace, en repoussant nos systèmes jusqu'aux limites et en obtenant des informations précieuses sur leurs capacités.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!