- 将现有练习及 module 文件迁移至 go/practice,保持代码和依赖不变 - 新增 go/projects 项目区说明,更新目录约定与开发命令 BREAKING CHANGE: Go 练习命令需改在 go/practice 目录下执行
51 lines
1.2 KiB
Go
51 lines
1.2 KiB
Go
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)
|
|
}
|