必须用 container/heap + 自定义结构体,因为 sync.pool 仅负责对象复用,不维护顺序、不支持优先级排序,无法实现优先级队列;需定义 task 结构体并实现 heap.interface 的 len、less、swap 方法,其中 less 比较 priority 字段。

直接用 sync.Pool 实现不了优先级队列
sync.Pool 只负责对象复用,不认识“任务”,也不管谁先跑、谁等一等。它没有 Push/Pop 接口,不维护顺序,更不会按 Priority 字段排序。拿它当优先级队列用,等于把调度逻辑全甩给上层代码——结果就是自己手写堆、加锁、控并发,sync.Pool 反而成了干扰项。
必须用 container/heap + 自定义结构体
Go 标准库没提供开箱即用的优先级队列,但 container/heap 足够轻量可控。关键不是堆快不快,而是你能否让任务稳定按 Priority 排序:
- 定义
Task结构体,带Priority int和Fn func()字段 - 实现
heap.Interface的Len()、Less(i, j int) bool、Swap(i, j int) -
Less必须写成pq[i].Priority 才能构建小根堆(数字越小,优先级越高) - 别漏掉
Push和Pop方法——它们要操作底层切片指针,否则heap.Push(&pq, task)不会真插入
heap 操作不是并发安全的,锁必须自己加
container/heap 是纯内存操作,零并发保护。多个 goroutine 同时调 Push/Pop,大概率 panic 或取错任务:
- 封装一层结构体,用
sync.Mutex包住所有堆操作:入队、出队、甚至Peek(看顶元素) - 锁粒度宁小勿大:只锁堆操作本身,别把
task.Fn()也包进去 - 修改任务
Priority后必须调heap.Fix(&pq, i),否则后续Pop返回错的任务 - 别用
select配多个 channel 模拟优先级——容易死锁或饥饿,且无法保证严格顺序
worker 协程池启动和停止要小心 goroutine 泄漏
worker 不能直接 for range 读 channel,因为优先级队列是内存结构,不走 channel。正确方式是循环 + 条件等待:
- 主循环里检查堆是否为空,空则
time.Sleep或用sync.Cond唤醒 - 有任务就
heap.Pop(&pq)执行,执行完再继续 - 关闭时设
closed bool标志位,循环中检查该标志并 break - 别用
close(taskCh)这类通道关闭方式通知停止——对堆无意义,反而可能 panic - 用
sync.WaitGroup等 worker 自然退出,否则 goroutine 泄漏不可避免
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











