func xHandle(w http.ResponseWriter, r *http.Request) {
fmt.Printf("new request: %p\n", r)
w.Write([]byte("Hello\n"))
for {}
}
func main() {
http.HandleFunc("/", xHandle)
http.ListenAndServe(":8080", nil)
}
对于每一个http请求,http服务都会启动一个go routine 来调用xHandle函数。目前搜到的资料都是在xHandle内部做并发数控制,就是说等http服务启go routine后,发现超限了再直接退出。
我想问的是如何从源头上控制http服务的go routine数量,也是当go routine到达上限后,都不用启动go routine回调xHandle,直接在底层响应500给客户端?
channel 应该可以实现,在goroutine启动之前从定长的channel里取值,取到就会继续执行,没取到就会阻塞,需要限制多少并发,就建多大的goroutine
#13
更多评论
```
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"time"
"golang.org/x/time/rate"
)
type LimiterOption struct {
lm *rate.Limiter
}
func WithLimiter(duration time.Duration, count int) func(o *LimiterOption) {
return func(o *LimiterOption) {
o.lm = rate.NewLimiter(rate.Every(duration), count)
}
}
// LimiterWrap 每个 handler 单独限制
func LimiterWrap(f http.HandlerFunc, opts ...func(o *LimiterOption)) http.HandlerFunc {
o := &LimiterOption{
lm: rate.NewLimiter(rate.Every(100*time.Millisecond), 10),
}
for _, opt := range opts {
opt(o)
}
return func(w http.ResponseWriter, r *http.Request) {
if !o.lm.Allow() {
w.WriteHeader(http.StatusInternalServerError)
return
}
f(w, r)
}
}
func xHandle(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello\n"))
}
func main() {
// 单独控制一个接口
http.HandleFunc("/", LimiterWrap(xHandle, WithLimiter(100*time.Millisecond, 1)))
// 所有接口都走同一个限流
// http.ListenAndServe(":8080", LimiterWrap(http.DefaultServeMux.ServeHTTP))
for i := 0; i < 10; i++ {
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/", nil)
http.DefaultServeMux.ServeHTTP(w, req)
fmt.Println(i, w.Code)
time.Sleep(time.Millisecond * 20)
}
//output
//0 200
//1 500
//2 500
//3 500
//4 500
//5 200
//6 500
//7 500
//8 500
//9 500
}
```
#1
```go
package main
func success() {}
func fail() {}
func main() {
c := make(chan struct{}, 16)
select {
case c <- struct{}{}:
success()
<-c
default:
fail()
}
}
```
#2