为什么主服务器goroutine处理传入请求会有这样的延迟?如何避免这种延迟?
带无延迟
的简单代码package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/", root)
http.ListenAndServe(":8090", nil)
}
//---------------------------------------------------------------------------
// http handlers
//---------------------------------------------------------------------------
func root(w http.ResponseWriter, r *http.Request) {
log.Printf("[root] `%v`\n", r.URL.Path)
w.Write([]byte("What the hell"))
}
测试加载的结果
╰─➤ wrk -d20s -t5 -c100 http://localhost:8090
Running 20s test @ http://localhost:8090
5 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 17.07ms 46.63ms 368.77ms 91.73%
Req/Sec 10.99k 4.87k 24.48k 62.49%
1038912 requests in 20.10s, 128.80MB read
Requests/sec: 51684.63
Transfer/sec: 6.41MB
添加goroutines
package main
import (
"log"
"net/http"
)
func main() {
_ = NewTesterGo(100)
http.HandleFunc("/", root)
http.ListenAndServe(":8090", nil)
}
//---------------------------------------------------------------------------
// http handlers
//---------------------------------------------------------------------------
func root(w http.ResponseWriter, r *http.Request) {
log.Printf("[root] `%v`\n", r.URL.Path)
w.Write([]byte("What the fuck"))
}
//---------------------------------------------------------------------------
// tester segment
//---------------------------------------------------------------------------
type (
TesterGo struct {
Work chan string
}
)
func NewTesterGo(count int) *TesterGo {
t:=&TesterGo{
Work:make(chan string,100),
}
for ; count > 0 ; count -- {
go t.Worker()
}
return t
}
func (t *TesterGo) Worker() {
log.Printf("[testergo][worker][work] стартовал....\n")
for {
select {
case work := <-t.Work:
log.Printf("[testerGo][Worker] %v\n", work)
default:
}
}
}
加载结果
╰─➤ wrk -d20s -t5 -c100 http://localhost:8090
Running 20s test @ http://localhost:8090
5 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 464.71ms 305.44ms 1.90s 77.90%
Req/Sec 54.62 43.74 200.00 67.50%
3672 requests in 20.05s, 466.17KB read
Socket errors: connect 0, read 0, write 0, **timeout 97**
Requests/sec: **183.11**
Transfer/sec: 23.25KB
答案 0 :(得分:4)
你的goroutines使用default
,如果频道中没有任何东西,它们会立即旋转(你的例子中没有任何内容)。这可能会使Go的调度程序更多地进行上下文切换,并且可能会消耗大量的CPU。
循环中有default
的原因吗?如果没有尝试以下之一:
要么没有默认值,goroutines就会简单地“睡觉”#34;直到那里工作。
for {
select {
case work := <-t.Work:
log.Printf("[testerGo][Worker] %v\n", work)
}
}
这个BTW使选择完全冗余,所以只是摆脱它:
for { //you can also use a range on the channel
work := <- t.Work
log.Printf("[testerGo][Worker] %v\n", work)
}
第二个选项 - 在继续循环之前使它们等待的超时:
for {
select {
case work := <-t.Work:
log.Printf("[testerGo][Worker] %v\n", work)
case <- time.After(100*time.Millisecond): //or whatever you prefer
}
}