代码地址 点击这里

并发限制(一种常见的做法就是利用 channel 的缓冲机制)

  1. var limitChan = make(chan bool, n)
  2. 如果 channel 没有缓冲,或者缓冲区满了。goroutine 会自动阻塞,直到 channel 里的数据被读走为止

代码演示

  1. var addr = flag.String("p", "192.168.2.28:8099", "port")
  2. func main() {
  3. flag.Parse()
  4. perf.StartPprof([]string{"192.168.2.28:9022"})
  5. logtool.InitZapLogger("ghost.log", true)
  6. //http服务
  7. mux := http.NewServeMux()
  8. mux.HandleFunc("/limit_api", limitApi)
  9. s := &http.Server{
  10. Handler: mux,
  11. Addr: *addr,
  12. WriteTimeout: 15 * time.Second,
  13. ReadTimeout: 15 * time.Second,
  14. MaxHeaderBytes: 1 << 20,
  15. }
  16. go func() {
  17. err := s.ListenAndServe()
  18. if err != nil {
  19. logtool.Zap.Panic("bat_file err", zap.Error(err))
  20. }
  21. }()
  22. quit.QuitSignal(func() {
  23. s.Close()
  24. fmt.Println("退出程序")
  25. })
  26. }
  27. var limitChan = make(chan bool, 1) //每次执行一个请求
  28. func limitApi(w http.ResponseWriter, r *http.Request) {
  29. select {
  30. case limitChan <- true:
  31. case <-time.After(2 * time.Second): //2秒不能写入服务器返回错误
  32. fmt.Println("服务器限流")
  33. w.Write([]byte("ERR"))
  34. return
  35. }
  36. //延迟释放limitChan 模拟超时
  37. rand.Seed(time.Now().UnixNano())
  38. time.Sleep(time.Duration(rand.Intn(4)) * time.Second)
  39. <-limitChan
  40. fmt.Println("服务器正常访问")
  41. w.Write([]byte("OK"))
  42. return
  43. }

控制台输出

  1. server start success pid:19309
  2. 服务器限流
  3. 服务器正常访问
  4. 服务器正常访问
  5. 服务器限流
  6. 服务器正常访问
  7. 服务器正常访问
  8. 服务器正常访问
  9. 退出程序

联系 QQ: 3355168235