package main import ( "context" "fmt" "math/rand" "net/http" _ "net/http/pprof" "time" ) // 来自文章 https://www.cnblogs.com/hwnd/p/20682814 func simulateRequest() { timeout := 500 * time.Millisecond ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(timeout)) defer cancel() resultCh := make(chan string) // 无缓冲! // 启动 worker goroutine 处理"请求" go func() { time.Sleep(time.Duration(rand.Intn(500)+300) * time.Millisecond) select { case <-time.After(timeout): fmt.Println("worker 超时,放弃处理") case <-ctx.Done(): case resultCh <- fmt.Sprintf("处理完成,耗时 %dms", rand.Intn(500)+300): } }() // TODO: 模拟请求取消或超时的情况(比如 500ms 后调用方不再关心结果) // 如果 worker 还没完成,它就 leak 了 select { case resultCh := <-resultCh: fmt.Println(resultCh) case <-ctx.Done(): fmt.Println("请求方取消了请求") } } func main() { for i := 0; i < 5; i++ { simulateRequest() fmt.Printf("第 %d 个请求处理完毕\n\n", i+1) time.Sleep(200 * time.Millisecond) } fmt.Println("所有请求处理完毕") // 运行后观察:goroutine 数量只增不减 http.ListenAndServe(":6060", nil) }