本文介绍一种基于 `sync.waitgroup` 和非阻塞通道发送的优雅方案,解决“工作池中每个任务可动态生成新任务”这一典型并发问题,避免死锁、竞态与资源浪费。
在构建爬虫、并行处理树状结构或执行可扩展异步任务时,常遇到一类特殊需求:初始一批任务启动后,每个任务在执行过程中可能动态产生新任务(如解析网页发现新链接),这些新任务需被同一工作池消费。此时,传统固定数量 goroutine + 简单 channel 模型易陷入僵局——所有 worker 同时阻塞在
核心挑战在于:既要保证任务不丢失、不重复,又要确保所有 worker 能安全退出(即无待处理任务且无活跃生产者)。原问题中尝试用 working 通道统计活跃 worker 数并关闭队列的方式,不仅逻辑复杂、易出竞态,还依赖对 select 执行顺序的误解(实际是随机公平选择),且无法应对“worker 自产自销”的递归场景。
推荐解法是采用 sync.WaitGroup 驱动生命周期 + 非阻塞通道回退机制,其关键设计如下: