https://github.com/panjf2000/ants/blob/master/README_ZH.md
-
性能测试做的很全面,具体方法总结
-
接口定义清晰,同时 demo 结合 defer 做资源释放
2.1. Submit、NewPoolWithFunc、Invoke、Release
2.2. Options -> WithXXArgOptions
-
使用文档清晰全面,同时还有运行时流程图
-
单元测试集中在 ants_test.go 文件,面向应用的行为(接口)在测试
优秀代码片段
- 自动设置 Pool 是阻塞的还是非阻塞的,防止单核频繁切换 Goroutine 调度:Inspired by fasthttp at https://github.com/valyala/fasthttp/blob/master/workerpool.go#L139
workerChanCap = func() int {
// Use blocking workerChan if GOMAXPROCS=1.
// This immediately switches Serve to WorkerFunc, which results
// in higher performance (under go1.5 at least).
if runtime.GOMAXPROCS(0) == 1 {
return 0
}
// Use non-blocking workerChan if GOMAXPROCS>1,
// since otherwise the Serve caller (Acceptor) may lag accepting
// new connections if WorkerFunc is CPU-bound.
return 1
}()
- 使用 atomic 原子操作代替锁,优点是啥?性能更高?
type spinLock uint32
func (sl *spinLock) Lock() {
for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
runtime.Gosched()
}
}
func (sl *spinLock) Unlock() {
atomic.StoreUint32((*uint32)(sl), 0)
}
// NewSpinLock instantiates a spin-lock.
func NewSpinLock() sync.Locker {
return new(spinLock)
}
- Goroutine 内存提前申请分配,有循环队列和栈两种管理类型
if p.options.PreAlloc {
p.workers = newWorkerArray(loopQueueType, size)
} else {
p.workers = newWorkerArray(stackType, 0)
}
loopQueueType 循环队列(维护首尾指针)提前分配好了内存,性能高
stackType 是一个可扩展长度的池(slice),每次从队尾获取/插入 Goroutine,节约内存;用二分查找来寻找过期的 Goroutine
- 使用 sync.Pool 来加速获取在运行的 worker,sync.Pool 是干啥的? 存储运行中的 Goroutine ?
博客:https://juejin.im/post/5d4087276fb9a06adb7fbe4a
-
workerArray 是存储已经申请的 Goroutine (不是在运行中的)进行池化,重复利用?
5.1. insert 插入空闲 Goroutine 到 workerArray
5.2. detach 从 workerArray 获取可用的 Goroutine