php小編西瓜注意到,使用Go語言進行多執行緒請求時,有時候並不能獲得高的請求每秒(RPS)速度。儘管Go語言在並發處理方面表現出色,但在某些情況下,多執行緒請求的效率並不高。這可能是由於網路延遲、資源競爭等因素導致的。在這篇文章中,我們將探討這個問題,並提供一些可能的解決方案來提高Go語言多執行緒請求的RPS。
我正在嘗試編寫一個多執行緒客戶端來測試我的伺服器。當我使用 2 個 goroutine 時,一切都很好,我得到 50k rps 並且我的 cpu 負載正常,但是當我創建超過 2 個 goroutine 時,rps 下降到 3k,但我的 cpu 負載超過了。儘管當我多次運行客戶端程式碼時(例如同時在 3 個控制台上運行相同的程式碼),我獲得了更多 rps,例如 80k rps。
這是我的客戶端程式碼
package main import ( "fmt" "net/http" "os" "sync" "time" ) func main() { requesturl := fmt.sprintf("http://localhost:%d/home", 3333) var wg sync.waitgroup wg.add(4) req, err := http.newrequest(http.methodget, requesturl, nil) if err != nil { fmt.printf("client: could not create request: %s\n", err) os.exit(1) } for i := 0; i < 4; i++ { go func() { defer wg.done() client := http.client{ timeout: 30 * time.second, } for { client.do(req) } }() } wg.wait() }
這是我的伺服器端程式碼
package main import ( "errors" "fmt" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "log" "net/http" "os" "sync" ) // log handling func openlogfile(path string) (*os.file, error) { logfile, err := os.openfile(path, os.o_wronly|os.o_append|os.o_create, 0644) if err != nil { return nil, err } return logfile, nil } // variables of counter in metric var okstatuscounter = prometheus.newcounter( prometheus.counteropts{ name: "ok_request_count", help: "number of 200", }, ) func listener(serverlog *log.logger) http.handlerfunc { return func(w http.responsewriter, r *http.request) { //metric okstatuscounter.inc() w.writeheader(http.statusok) } } func main() { //metric prometheus.mustregister(okstatuscounter) //log handling filesimpleserverlog, err := openlogfile("simpleserver/simpleserverlog.log") if err != nil { log.fatal(err) } serverlog := log.new(filesimpleserverlog, "[simple server]", log.lstdflags|log.lshortfile|log.lmicroseconds) var wg sync.waitgroup wg.add(1) //server: go func() { defer wg.done() mux := http.newservemux() mux.handlefunc("/home", listener(serverlog)) mux.handle("/metrics", promhttp.handler()) server := http.server{ addr: fmt.sprintf(":%d", 3333), handler: mux, } if err := server.listenandserve(); err != nil { if !errors.is(err, http.errserverclosed) { serverlog.printf("error running http server: %s\n", err) } } }() wg.wait() }
一開始我以為 go 可能會使用一個連接埠來進行所有客戶端連接,但是當我用 netstat 檢查它時,它使用了多個連接埠。我嘗試搜尋但找不到合適的答案
我嘗試了sync.mutex:
var mu sync.Mutex ... for i := 0; i < 1000; i++ { go func() { defer wg.Done() client := http.Client{ //Timeout: 30 * time.Second, } for { mu.Lock() _, err := client.Do(req) if err != nil { clientLog.Printf("client: error making http request: %s\n", err) os.Exit(1) } mu.Unlock() } }() } wg.Wait() ...
透過上述更改,我獲得了13k rps,並且我的cpu 負載正常,但這根本不夠
由於您僅向一台主機發送請求,因此http傳輸的預設值不適合您。最好根據您的情況手動設定參數:
t := http.DefaultTransport.(*http.Transport).Clone() t.MaxIdleConns = 100 t.MaxConnsPerHost = 100 t.MaxIdleConnsPerHost = 100 httpClient = &http.Client{ Timeout: 10 * time.Second, Transport: t, }
有關更多信息,您可以閱讀這裡。
以上是go 中的多線程請求並且沒有獲得高 RPS的詳細內容。更多資訊請關注PHP中文網其他相關文章!