Go中goroutine非线程,不可无限制创建,否则引发泛滥、连接池耗尽、DNS超时及限流;需配合连接池、限流与超时控制。

Go里没有“每个请求一个进程/线程”的天然隔离层,直接照搬PHP-FPM或Swoole的并发习惯会触发goroutine泛滥、连接池打满、DNS超时甚至被限流——这不是配置问题,是模型错配。
goroutine不是thread,不能无限制起
PHP开发者常写for i := 0; i ,看似并发,实则可能瞬间拉起上千goroutine。而Python线程有OS级数量压制,goroutine没有。
- 必须显式限流:用
semaphore(如golang.org/x/sync/semaphore)或sync.WaitGroup+ 缓冲channel控制并发数,例如最多10个HTTP请求同时发出 - 别用
time.Sleep模拟等待:它会阻塞整个goroutine;该用select配合time.After做非阻塞超时 - HTTP客户端必须复用:
http.Client要提前初始化,并设置Transport.MaxIdleConns、MaxIdleConnsPerHost等参数,否则每个goroutine都建新TCP连接
channel + select 替代 async/await
Python里await asyncio.gather(a(), b(), c())自动调度多个协程并收结果;Go没有事件循环,所有协作必须靠channel显式传递信号。
- 正确模式:启动3个goroutine分别调API,把结果或错误发到同一个
chan Result;主goroutine用for i := 0; i 收齐 - channel容量要明确:无缓冲channel(
make(chan int))会阻塞发送方,直到有接收方就绪;有缓冲(make(chan int, 10))可缓解突发,但不解决逻辑耦合 -
select默认非阻塞需加default分支;超时必须走case ,不能<code>time.Sleep后发消息
context.Context不是装饰器,是取消凭证
PHP里@timeout(5)或Python里asyncio.wait_for是一层包装;Go的context.Context必须手动传入每个可能阻塞的函数调用点。
立即学习“PHP免费学习笔记(深入)”;
- HTTP请求要用
http.NewRequestWithContext(ctx, ...) - 数据库操作要用
db.QueryRowContext(ctx, ...) - 自定义函数参数里也得显式加
ctx context.Context,并在内部用select监听ctx.Done() - 别把
context.Background()存成包级变量——它无法被取消,且跨goroutine传递易导致泄漏
最易忽略的一点:goroutine生命周期和HTTP请求生命周期不绑定。一个handler返回后,里面启的goroutine若没受context约束或没等WaitGroup,就会变成孤儿goroutine,持续占用内存和连接。



















