如何一次性唤醒0至N个休眠的Goroutines?最优方案探讨
Goroutine等待与批量通知的最优方案问题
我正在编写一个程序,通过命令行参数N启动N个工作Goroutine。任何时刻都可能有0至N-1个Goroutine等待其他Goroutine更新某个变量。需要找到两个最优方案:
- Goroutine等待该变量更新事件的最佳方式
- 单个Goroutine一次性通知所有其他Goroutine事件发生的最优方案
且该事件会被每个Goroutine多次触发。
排除的工具说明
sync.Cond并不适用:因为Goroutine被唤醒后无需锁定资源sync.WaitGroup也无法使用:因为无法预知需要调用多少次wg.Done()
现有方案分析
方案一:基于sync.Mutex的通知方式
让负责通知的Goroutine先获取锁再释放锁来触发通知,但当所有Goroutine被唤醒后,仅需读取变量判断是否成为主工作线程,再决定继续休眠或开始工作,这种锁竞争的方式效率极低。
方案二:包装sync.WaitGroup跟踪等待数
为sync.WaitGroup创建包装器,用于跟踪等待Goroutine的数量,以便调用wg.Add(-numWaitingThreads)来唤醒所有等待者,但编码时极易出现各种竞态条件,实现起来非常繁琐。
方案三:多通道非阻塞通知
创建一个包含N个通道的列表,通知方向除自身外的所有通道执行非阻塞发送。但不确定这是否为最佳方案。
业务逻辑细节
每个工作Goroutine分配有唯一的信用标识(credit),同时设置一个中央变量centralNextCreditID,记录“下一个要写入输出文件的信用ID”。当工作Goroutine完成当前信用ID的任务后,需要执行以下逻辑:
for centralNextCreditID != creditID { wait_for_centralNextCreditID_to_change() // 等待centralNextCreditID更新 } saveWorkToFile() // 将工作成果保存到文件 centralNextCreditID++ // 更新中央变量 wake_other_threads_waiting_for_centralNextCreditID_to_change() // 唤醒其他等待该变量更新的线程
内容的提问来源于stack exchange,提问作者ILoveGit
相关产品推荐
相关产品推荐

