From 4d253634cf45a996ecaea54f86cd5127857e089d Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sun, 12 Jan 2025 21:49:50 +0800 Subject: [PATCH] test: add some basic testable examples --- README.md | 203 ++------------------ README_ZH.md | 197 ++----------------- ants_benchmark_test.go | 16 +- ants_test.go | 394 +++++++++++++++++++------------------- example_test.go | 174 +++++++++++++++++ examples/main.go | 114 ----------- options.go | 22 +++ worker_loop_queue.go | 22 +++ worker_loop_queue_test.go | 27 ++- worker_queue.go | 22 +++ worker_stack.go | 22 +++ worker_stack_test.go | 27 ++- 12 files changed, 546 insertions(+), 694 deletions(-) create mode 100644 example_test.go delete mode 100644 examples/main.go diff --git a/README.md b/README.md index ccdff4a..fc86e12 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Library `ants` implements a goroutine pool with fixed capacity, managing and rec - Purging overdue goroutines periodically - Abundant APIs: submitting tasks, getting the number of running goroutines, tuning the capacity of the pool dynamically, releasing the pool, rebooting the pool, etc. - Handle panic gracefully to prevent programs from crash -- Efficient in memory usage and it may even achieve ***higher performance*** than unlimited goroutines in Golang +- Efficient in memory usage and it may even achieve ***higher performance*** than unlimited goroutines in Go - Nonblocking mechanism - Preallocated memory (ring buffer, optional) @@ -62,205 +62,30 @@ go get -u github.com/panjf2000/ants/v2 ``` ## 🛠 How to use -Just imagine that your program starts a massive number of goroutines, resulting in a huge consumption of memory. To mitigate that kind of situation, all you need to do is to import `ants` package and submit all your tasks to a default pool with fixed capacity, activated when package `ants` is imported: +Check out [the examples](https://pkg.go.dev/github.com/panjf2000/ants/v2#pkg-examples) for basic usage. -``` go -package main - -import ( - "fmt" - "sync" - "sync/atomic" - "time" - - "github.com/panjf2000/ants/v2" -) - -var sum int32 - -func myFunc(i any) { - n := i.(int32) - atomic.AddInt32(&sum, n) - fmt.Printf("run with %d\n", n) -} - -func demoFunc() { - time.Sleep(10 * time.Millisecond) - fmt.Println("Hello World!") -} - -func main() { - defer ants.Release() - - runTimes := 1000 - - // Use the common pool. - var wg sync.WaitGroup - syncCalculateSum := func() { - demoFunc() - wg.Done() - } - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = ants.Submit(syncCalculateSum) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", ants.Running()) - fmt.Printf("finish all tasks.\n") - - // Use the pool with a function, - // set 10 to the capacity of goroutine pool and 1 second for expired duration. - p, _ := ants.NewPoolWithFunc(10, func(i any) { - myFunc(i) - wg.Done() - }) - defer p.Release() - // Submit tasks one by one. - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = p.Invoke(int32(i)) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", p.Running()) - fmt.Printf("finish all tasks, result is %d\n", sum) - if sum != 499500 { - panic("the final result is wrong!!!") - } - - // Use the MultiPool and set the capacity of the 10 goroutine pools to unlimited. - // If you use -1 as the pool size parameter, the size will be unlimited. - // There are two load-balancing algorithms for pools: ants.RoundRobin and ants.LeastTasks. - mp, _ := ants.NewMultiPool(10, -1, ants.RoundRobin) - defer mp.ReleaseTimeout(5 * time.Second) - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = mp.Submit(syncCalculateSum) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", mp.Running()) - fmt.Printf("finish all tasks.\n") - - // Use the MultiPoolFunc and set the capacity of 10 goroutine pools to (runTimes/10). - mpf, _ := ants.NewMultiPoolWithFunc(10, runTimes/10, func(i any) { - myFunc(i) - wg.Done() - }, ants.LeastTasks) - defer mpf.ReleaseTimeout(5 * time.Second) - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = mpf.Invoke(int32(i)) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", mpf.Running()) - fmt.Printf("finish all tasks, result is %d\n", sum) - if sum != 499500*2 { - panic("the final result is wrong!!!") - } -} -``` - -### Functional options for ants pool +### Functional options for pool -```go -// Option represents the optional function. -type Option func(opts *Options) - -// Options contains all options which will be applied when instantiating a ants pool. -type Options struct { - // ExpiryDuration is a period for the scavenger goroutine to clean up those expired workers, - // the scavenger scans all workers every `ExpiryDuration` and clean up those workers that haven't been - // used for more than `ExpiryDuration`. - ExpiryDuration time.Duration - - // PreAlloc indicates whether to make memory pre-allocation when initializing Pool. - PreAlloc bool - - // Max number of goroutine blocking on pool.Submit. - // 0 (default value) means no such limit. - MaxBlockingTasks int - - // When Nonblocking is true, Pool.Submit will never be blocked. - // ErrPoolOverload will be returned when Pool.Submit cannot be done at once. - // When Nonblocking is true, MaxBlockingTasks is inoperative. - Nonblocking bool - - // PanicHandler is used to handle panics from each worker goroutine. - // if nil, panics will be thrown out again from worker goroutines. - PanicHandler func(any) - - // Logger is the customized logger for logging info, if it is not set, - // default standard logger from log package is used. - Logger Logger -} - -// WithOptions accepts the whole options config. -func WithOptions(options Options) Option { - return func(opts *Options) { - *opts = options - } -} - -// WithExpiryDuration sets up the interval time of cleaning up goroutines. -func WithExpiryDuration(expiryDuration time.Duration) Option { - return func(opts *Options) { - opts.ExpiryDuration = expiryDuration - } -} - -// WithPreAlloc indicates whether it should malloc for workers. -func WithPreAlloc(preAlloc bool) Option { - return func(opts *Options) { - opts.PreAlloc = preAlloc - } -} - -// WithMaxBlockingTasks sets up the maximum number of goroutines that are blocked when it reaches the capacity of pool. -func WithMaxBlockingTasks(maxBlockingTasks int) Option { - return func(opts *Options) { - opts.MaxBlockingTasks = maxBlockingTasks - } -} - -// WithNonblocking indicates that pool will return nil when there is no available workers. -func WithNonblocking(nonblocking bool) Option { - return func(opts *Options) { - opts.Nonblocking = nonblocking - } -} - -// WithPanicHandler sets up panic handler. -func WithPanicHandler(panicHandler func(any)) Option { - return func(opts *Options) { - opts.PanicHandler = panicHandler - } -} - -// WithLogger sets up a customized logger. -func WithLogger(logger Logger) Option { - return func(opts *Options) { - opts.Logger = logger - } -} -``` +`ants.Options`contains all optional configurations of the ants pool, which allows you to customize the goroutine pool by invoking option functions to set up each configuration in `NewPool`/`NewPoolWithFunc`/`NewPoolWithFuncGeneric` method. -`ants.Options`contains all optional configurations of the ants pool, which allows you to customize the goroutine pool by invoking option functions to set up each configuration in `NewPool`/`NewPoolWithFunc`method. +Check out [ants.Options](https://pkg.go.dev/github.com/panjf2000/ants/v2#Options) and [ants.Option](https://pkg.go.dev/github.com/panjf2000/ants/v2#Option) for more details. -### Customize limited pool +### Customize pool capacity -`ants` also supports customizing the capacity of the pool. You can invoke the `NewPool` method to instantiate a pool with a given capacity, as follows: +`ants` supports customizing the capacity of the pool. You can call the `NewPool` method to instantiate a `Pool` with a given capacity, as follows: ``` go p, _ := ants.NewPool(10000) ``` ### Submit tasks -Tasks can be submitted by calling `ants.Submit(func())` +Tasks can be submitted by calling `ants.Submit` ```go ants.Submit(func(){}) ``` -### Tune pool capacity in runtime -You can tune the capacity of `ants` pool in runtime with `Tune(int)`: +### Tune pool capacity at runtime +You can tune the capacity of `ants` pool at runtime with `ants.Tune`: ``` go pool.Tune(1000) // Tune its capacity to 1000 @@ -274,11 +99,11 @@ Don't worry about the contention problems in this case, the method here is threa `ants` allows you to pre-allocate the memory of the goroutine queue in the pool, which may get a performance enhancement under some special certain circumstances such as the scenario that requires a pool with ultra-large capacity, meanwhile, each task in goroutine lasts for a long time, in this case, pre-mallocing will reduce a lot of memory allocation in goroutine queue. ```go -// ants will pre-malloc the whole capacity of pool when you invoke this method +// ants will pre-malloc the whole capacity of pool when calling ants.NewPool. p, _ := ants.NewPool(100000, ants.WithPreAlloc(true)) ``` -### Release Pool +### Release pool ```go pool.Release() @@ -290,10 +115,10 @@ or pool.ReleaseTimeout(time.Second * 3) ``` -### Reboot Pool +### Reboot pool ```go -// A pool that has been released can be still used once you invoke the Reboot(). +// A pool that has been released can be still used after calling the Reboot(). pool.Reboot() ``` diff --git a/README_ZH.md b/README_ZH.md index 275e539..e0c323c 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -17,7 +17,7 @@ ## 📖 简介 -`ants`是一个高性能的 goroutine 池,实现了对大规模 goroutine 的调度管理、goroutine 复用,允许使用者在开发并发程序的时候限制 goroutine 数量,复用资源,达到更高效执行任务的效果。 +`ants` 是一个高性能的 goroutine 池,实现了对大规模 goroutine 的调度管理、goroutine 复用,允许使用者在开发并发程序的时候限制 goroutine 数量,复用资源,达到更高效执行任务的效果。 ## 🚀 功能: @@ -25,7 +25,7 @@ - 定期清理过期的 goroutines,进一步节省资源 - 提供了大量实用的接口:任务提交、获取运行中的 goroutine 数量、动态调整 Pool 大小、释放 Pool、重启 Pool 等 - 优雅处理 panic,防止程序崩溃 -- 资源复用,极大节省内存使用量;在大规模批量并发任务场景下甚至可能比原生 goroutine 并发具有***更高的性能*** +- 资源复用,极大节省内存使用量;在大规模批量并发任务场景下甚至可能比 Go 语言的无限制 goroutine 并发具有***更高的性能*** - 非阻塞机制 - 预分配内存 (环形队列,可选) @@ -62,192 +62,17 @@ go get -u github.com/panjf2000/ants/v2 ``` ## 🛠 使用 -写 go 并发程序的时候如果程序会启动大量的 goroutine ,势必会消耗大量的系统资源(内存,CPU),通过使用 `ants`,可以实例化一个 goroutine 池,复用 goroutine ,节省资源,提升性能: - -``` go -package main - -import ( - "fmt" - "sync" - "sync/atomic" - "time" - - "github.com/panjf2000/ants/v2" -) - -var sum int32 - -func myFunc(i any) { - n := i.(int32) - atomic.AddInt32(&sum, n) - fmt.Printf("run with %d\n", n) -} - -func demoFunc() { - time.Sleep(10 * time.Millisecond) - fmt.Println("Hello World!") -} - -func main() { - defer ants.Release() - - runTimes := 1000 - - // Use the common pool. - var wg sync.WaitGroup - syncCalculateSum := func() { - demoFunc() - wg.Done() - } - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = ants.Submit(syncCalculateSum) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", ants.Running()) - fmt.Printf("finish all tasks.\n") - - // Use the pool with a function, - // set 10 to the capacity of goroutine pool and 1 second for expired duration. - p, _ := ants.NewPoolWithFunc(10, func(i any) { - myFunc(i) - wg.Done() - }) - defer p.Release() - // Submit tasks one by one. - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = p.Invoke(int32(i)) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", p.Running()) - fmt.Printf("finish all tasks, result is %d\n", sum) - if sum != 499500 { - panic("the final result is wrong!!!") - } - - // Use the MultiPool and set the capacity of the 10 goroutine pools to unlimited. - // If you use -1 as the pool size parameter, the size will be unlimited. - // There are two load-balancing algorithms for pools: ants.RoundRobin and ants.LeastTasks. - mp, _ := ants.NewMultiPool(10, -1, ants.RoundRobin) - defer mp.ReleaseTimeout(5 * time.Second) - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = mp.Submit(syncCalculateSum) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", mp.Running()) - fmt.Printf("finish all tasks.\n") - - // Use the MultiPoolFunc and set the capacity of 10 goroutine pools to (runTimes/10). - mpf, _ := ants.NewMultiPoolWithFunc(10, runTimes/10, func(i any) { - myFunc(i) - wg.Done() - }, ants.LeastTasks) - defer mpf.ReleaseTimeout(5 * time.Second) - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = mpf.Invoke(int32(i)) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", mpf.Running()) - fmt.Printf("finish all tasks, result is %d\n", sum) - if sum != 499500*2 { - panic("the final result is wrong!!!") - } -} -``` +基本的使用请查看[示例](https://pkg.go.dev/github.com/panjf2000/ants/v2#pkg-examples). ### Pool 配置 -```go -// Option represents the optional function. -type Option func(opts *Options) - -// Options contains all options which will be applied when instantiating a ants pool. -type Options struct { - // ExpiryDuration is a period for the scavenger goroutine to clean up those expired workers, - // the scavenger scans all workers every `ExpiryDuration` and clean up those workers that haven't been - // used for more than `ExpiryDuration`. - ExpiryDuration time.Duration - - // PreAlloc indicates whether to make memory pre-allocation when initializing Pool. - PreAlloc bool - - // Max number of goroutine blocking on pool.Submit. - // 0 (default value) means no such limit. - MaxBlockingTasks int - - // When Nonblocking is true, Pool.Submit will never be blocked. - // ErrPoolOverload will be returned when Pool.Submit cannot be done at once. - // When Nonblocking is true, MaxBlockingTasks is inoperative. - Nonblocking bool - - // PanicHandler is used to handle panics from each worker goroutine. - // if nil, panics will be thrown out again from worker goroutines. - PanicHandler func(any) - - // Logger is the customized logger for logging info, if it is not set, - // default standard logger from log package is used. - Logger Logger -} - -// WithOptions accepts the whole options config. -func WithOptions(options Options) Option { - return func(opts *Options) { - *opts = options - } -} - -// WithExpiryDuration sets up the interval time of cleaning up goroutines. -func WithExpiryDuration(expiryDuration time.Duration) Option { - return func(opts *Options) { - opts.ExpiryDuration = expiryDuration - } -} - -// WithPreAlloc indicates whether it should malloc for workers. -func WithPreAlloc(preAlloc bool) Option { - return func(opts *Options) { - opts.PreAlloc = preAlloc - } -} - -// WithMaxBlockingTasks sets up the maximum number of goroutines that are blocked when it reaches the capacity of pool. -func WithMaxBlockingTasks(maxBlockingTasks int) Option { - return func(opts *Options) { - opts.MaxBlockingTasks = maxBlockingTasks - } -} - -// WithNonblocking indicates that pool will return nil when there is no available workers. -func WithNonblocking(nonblocking bool) Option { - return func(opts *Options) { - opts.Nonblocking = nonblocking - } -} - -// WithPanicHandler sets up panic handler. -func WithPanicHandler(panicHandler func(any)) Option { - return func(opts *Options) { - opts.PanicHandler = panicHandler - } -} - -// WithLogger sets up a customized logger. -func WithLogger(logger Logger) Option { - return func(opts *Options) { - opts.Logger = logger - } -} -``` +通过在调用 `NewPool`/`NewPoolWithFunc`/`NewPoolWithFuncGeneric` 之时使用各种 optional function,可以设置 `ants.Options` 中各个配置项的值,然后用它来定制化 goroutine pool。 -通过在调用`NewPool`/`NewPoolWithFunc`之时使用各种 optional function,可以设置`ants.Options`中各个配置项的值,然后用它来定制化 goroutine pool. +更多细节请查看 [ants.Options](https://pkg.go.dev/github.com/panjf2000/ants/v2#Options) 和 [ants.Option](https://pkg.go.dev/github.com/panjf2000/ants/v2#Option) -### 自定义池 -`ants`支持实例化使用者自己的一个 Pool ,指定具体的池容量;通过调用 `NewPool` 方法可以实例化一个新的带有指定容量的 Pool ,如下: +### 自定义 pool 容量 +`ants` 支持实例化使用者自己的一个 Pool,指定具体的 pool 容量;通过调用 `NewPool` 方法可以实例化一个新的带有指定容量的 `Pool`,如下: ``` go p, _ := ants.NewPool(10000) @@ -255,13 +80,13 @@ p, _ := ants.NewPool(10000) ### 任务提交 -提交任务通过调用 `ants.Submit(func())`方法: +提交任务通过调用 `ants.Submit` 方法: ```go ants.Submit(func(){}) ``` ### 动态调整 goroutine 池容量 -需要动态调整 goroutine 池容量可以通过调用`Tune(int)`: +需要动态调整 pool 容量可以通过调用 `ants.Tune`: ``` go pool.Tune(1000) // Tune its capacity to 1000 @@ -272,10 +97,10 @@ pool.Tune(100000) // Tune its capacity to 100000 ### 预先分配 goroutine 队列内存 -`ants`允许你预先把整个池的容量分配内存, 这个功能可以在某些特定的场景下提高 goroutine 池的性能。比如, 有一个场景需要一个超大容量的池,而且每个 goroutine 里面的任务都是耗时任务,这种情况下,预先分配 goroutine 队列内存将会减少不必要的内存重新分配。 +`ants` 支持预先为 pool 分配容量的内存, 这个功能可以在某些特定的场景下提高 goroutine 池的性能。比如, 有一个场景需要一个超大容量的池,而且每个 goroutine 里面的任务都是耗时任务,这种情况下,预先分配 goroutine 队列内存将会减少不必要的内存重新分配。 ```go -// ants will pre-malloc the whole capacity of pool when you invoke this function +// 提前分配的 pool 容量的内存空间 p, _ := ants.NewPool(100000, ants.WithPreAlloc(true)) ``` diff --git a/ants_benchmark_test.go b/ants_benchmark_test.go index 33b4c1e..38e25dc 100644 --- a/ants_benchmark_test.go +++ b/ants_benchmark_test.go @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -package ants +package ants_test import ( "runtime" @@ -30,6 +30,8 @@ import ( "time" "golang.org/x/sync/errgroup" + + "github.com/panjf2000/ants/v2" ) const ( @@ -122,7 +124,7 @@ func BenchmarkErrGroup(b *testing.B) { func BenchmarkAntsPool(b *testing.B) { var wg sync.WaitGroup - p, _ := NewPool(PoolCap, WithExpiryDuration(DefaultExpiredTime)) + p, _ := ants.NewPool(PoolCap, ants.WithExpiryDuration(DefaultExpiredTime)) defer p.Release() b.ResetTimer() @@ -140,7 +142,7 @@ func BenchmarkAntsPool(b *testing.B) { func BenchmarkAntsMultiPool(b *testing.B) { var wg sync.WaitGroup - p, _ := NewMultiPool(10, PoolCap/10, RoundRobin, WithExpiryDuration(DefaultExpiredTime)) + p, _ := ants.NewMultiPool(10, PoolCap/10, ants.RoundRobin, ants.WithExpiryDuration(DefaultExpiredTime)) defer p.ReleaseTimeout(DefaultExpiredTime) //nolint:errcheck b.ResetTimer() @@ -178,7 +180,7 @@ func BenchmarkSemaphoreThroughput(b *testing.B) { } func BenchmarkAntsPoolThroughput(b *testing.B) { - p, _ := NewPool(PoolCap, WithExpiryDuration(DefaultExpiredTime)) + p, _ := ants.NewPool(PoolCap, ants.WithExpiryDuration(DefaultExpiredTime)) defer p.Release() b.ResetTimer() @@ -190,7 +192,7 @@ func BenchmarkAntsPoolThroughput(b *testing.B) { } func BenchmarkAntsMultiPoolThroughput(b *testing.B) { - p, _ := NewMultiPool(10, PoolCap/10, RoundRobin, WithExpiryDuration(DefaultExpiredTime)) + p, _ := ants.NewMultiPool(10, PoolCap/10, ants.RoundRobin, ants.WithExpiryDuration(DefaultExpiredTime)) defer p.ReleaseTimeout(DefaultExpiredTime) //nolint:errcheck b.ResetTimer() @@ -202,7 +204,7 @@ func BenchmarkAntsMultiPoolThroughput(b *testing.B) { } func BenchmarkParallelAntsPoolThroughput(b *testing.B) { - p, _ := NewPool(PoolCap, WithExpiryDuration(DefaultExpiredTime)) + p, _ := ants.NewPool(PoolCap, ants.WithExpiryDuration(DefaultExpiredTime)) defer p.Release() b.ResetTimer() @@ -214,7 +216,7 @@ func BenchmarkParallelAntsPoolThroughput(b *testing.B) { } func BenchmarkParallelAntsMultiPoolThroughput(b *testing.B) { - p, _ := NewMultiPool(10, PoolCap/10, RoundRobin, WithExpiryDuration(DefaultExpiredTime)) + p, _ := ants.NewMultiPool(10, PoolCap/10, ants.RoundRobin, ants.WithExpiryDuration(DefaultExpiredTime)) defer p.ReleaseTimeout(DefaultExpiredTime) //nolint:errcheck b.ResetTimer() diff --git a/ants_test.go b/ants_test.go index 316497d..8fc1d5f 100644 --- a/ants_test.go +++ b/ants_test.go @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -package ants +package ants_test import ( "log" @@ -32,6 +32,8 @@ import ( "time" "github.com/stretchr/testify/require" + + "github.com/panjf2000/ants/v2" ) const ( @@ -52,7 +54,7 @@ var curMem uint64 // TestAntsPoolWaitToGetWorker is used to test waiting to get worker. func TestAntsPoolWaitToGetWorker(t *testing.T) { var wg sync.WaitGroup - p, _ := NewPool(AntsSize) + p, _ := ants.NewPool(AntsSize) defer p.Release() for i := 0; i < n; i++ { @@ -72,7 +74,7 @@ func TestAntsPoolWaitToGetWorker(t *testing.T) { func TestAntsPoolWaitToGetWorkerPreMalloc(t *testing.T) { var wg sync.WaitGroup - p, _ := NewPool(AntsSize, WithPreAlloc(true)) + p, _ := ants.NewPool(AntsSize, ants.WithPreAlloc(true)) defer p.Release() for i := 0; i < n; i++ { @@ -93,7 +95,7 @@ func TestAntsPoolWaitToGetWorkerPreMalloc(t *testing.T) { // TestAntsPoolWithFuncWaitToGetWorker is used to test waiting to get worker. func TestAntsPoolWithFuncWaitToGetWorker(t *testing.T) { var wg sync.WaitGroup - p, _ := NewPoolWithFunc(AntsSize, func(i any) { + p, _ := ants.NewPoolWithFunc(AntsSize, func(i any) { demoPoolFunc(i) wg.Done() }) @@ -114,7 +116,7 @@ func TestAntsPoolWithFuncWaitToGetWorker(t *testing.T) { // TestAntsPoolWithFuncGenericWaitToGetWorker is used to test waiting to get worker. func TestAntsPoolWithFuncGenericWaitToGetWorker(t *testing.T) { var wg sync.WaitGroup - p, _ := NewPoolWithFuncGeneric(AntsSize, func(i int) { + p, _ := ants.NewPoolWithFuncGeneric(AntsSize, func(i int) { demoPoolFuncInt(i) wg.Done() }) @@ -134,10 +136,10 @@ func TestAntsPoolWithFuncGenericWaitToGetWorker(t *testing.T) { func TestAntsPoolWithFuncWaitToGetWorkerPreMalloc(t *testing.T) { var wg sync.WaitGroup - p, _ := NewPoolWithFunc(AntsSize, func(i any) { + p, _ := ants.NewPoolWithFunc(AntsSize, func(i any) { demoPoolFunc(i) wg.Done() - }, WithPreAlloc(true)) + }, ants.WithPreAlloc(true)) defer p.Release() for i := 0; i < n; i++ { @@ -154,10 +156,10 @@ func TestAntsPoolWithFuncWaitToGetWorkerPreMalloc(t *testing.T) { func TestAntsPoolWithFuncGenericWaitToGetWorkerPreMalloc(t *testing.T) { var wg sync.WaitGroup - p, _ := NewPoolWithFuncGeneric(AntsSize, func(i int) { + p, _ := ants.NewPoolWithFuncGeneric(AntsSize, func(i int) { demoPoolFuncInt(i) wg.Done() - }, WithPreAlloc(true)) + }, ants.WithPreAlloc(true)) defer p.Release() for i := 0; i < n; i++ { @@ -174,13 +176,13 @@ func TestAntsPoolWithFuncGenericWaitToGetWorkerPreMalloc(t *testing.T) { // TestAntsPoolGetWorkerFromCache is used to test getting worker from sync.Pool. func TestAntsPoolGetWorkerFromCache(t *testing.T) { - p, _ := NewPool(TestSize) + p, _ := ants.NewPool(TestSize) defer p.Release() for i := 0; i < AntsSize; i++ { _ = p.Submit(demoFunc) } - time.Sleep(2 * DefaultCleanIntervalTime) + time.Sleep(2 * ants.DefaultCleanIntervalTime) _ = p.Submit(demoFunc) t.Logf("pool, running workers number:%d", p.Running()) mem := runtime.MemStats{} @@ -192,13 +194,13 @@ func TestAntsPoolGetWorkerFromCache(t *testing.T) { // TestAntsPoolWithFuncGetWorkerFromCache is used to test getting worker from sync.Pool. func TestAntsPoolWithFuncGetWorkerFromCache(t *testing.T) { dur := 10 - p, _ := NewPoolWithFunc(TestSize, demoPoolFunc) + p, _ := ants.NewPoolWithFunc(TestSize, demoPoolFunc) defer p.Release() for i := 0; i < AntsSize; i++ { _ = p.Invoke(dur) } - time.Sleep(2 * DefaultCleanIntervalTime) + time.Sleep(2 * ants.DefaultCleanIntervalTime) _ = p.Invoke(dur) t.Logf("pool with func, running workers number:%d", p.Running()) mem := runtime.MemStats{} @@ -210,13 +212,13 @@ func TestAntsPoolWithFuncGetWorkerFromCache(t *testing.T) { // TestAntsPoolWithFuncGenericGetWorkerFromCache is used to test getting worker from sync.Pool. func TestAntsPoolWithFuncGenericGetWorkerFromCache(t *testing.T) { dur := 10 - p, _ := NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt) + p, _ := ants.NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt) defer p.Release() for i := 0; i < AntsSize; i++ { _ = p.Invoke(dur) } - time.Sleep(2 * DefaultCleanIntervalTime) + time.Sleep(2 * ants.DefaultCleanIntervalTime) _ = p.Invoke(dur) t.Logf("pool with func, running workers number:%d", p.Running()) mem := runtime.MemStats{} @@ -227,13 +229,13 @@ func TestAntsPoolWithFuncGenericGetWorkerFromCache(t *testing.T) { func TestAntsPoolWithFuncGetWorkerFromCachePreMalloc(t *testing.T) { dur := 10 - p, _ := NewPoolWithFunc(TestSize, demoPoolFunc, WithPreAlloc(true)) + p, _ := ants.NewPoolWithFunc(TestSize, demoPoolFunc, ants.WithPreAlloc(true)) defer p.Release() for i := 0; i < AntsSize; i++ { _ = p.Invoke(dur) } - time.Sleep(2 * DefaultCleanIntervalTime) + time.Sleep(2 * ants.DefaultCleanIntervalTime) _ = p.Invoke(dur) t.Logf("pool with func, running workers number:%d", p.Running()) mem := runtime.MemStats{} @@ -244,13 +246,13 @@ func TestAntsPoolWithFuncGetWorkerFromCachePreMalloc(t *testing.T) { func TestAntsPoolWithFuncGenericGetWorkerFromCachePreMalloc(t *testing.T) { dur := 10 - p, _ := NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt, WithPreAlloc(true)) + p, _ := ants.NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt, ants.WithPreAlloc(true)) defer p.Release() for i := 0; i < AntsSize; i++ { _ = p.Invoke(dur) } - time.Sleep(2 * DefaultCleanIntervalTime) + time.Sleep(2 * ants.DefaultCleanIntervalTime) _ = p.Invoke(dur) t.Logf("pool with func, running workers number:%d", p.Running()) mem := runtime.MemStats{} @@ -279,20 +281,20 @@ func TestNoPool(t *testing.T) { } func TestAntsPool(t *testing.T) { - defer Release() + defer ants.Release() var wg sync.WaitGroup for i := 0; i < n; i++ { wg.Add(1) - _ = Submit(func() { + _ = ants.Submit(func() { demoFunc() wg.Done() }) } wg.Wait() - t.Logf("pool, capacity:%d", Cap()) - t.Logf("pool, running workers number:%d", Running()) - t.Logf("pool, free workers number:%d", Free()) + t.Logf("pool, capacity:%d", ants.Cap()) + t.Logf("pool, running workers number:%d", ants.Running()) + t.Logf("pool, free workers number:%d", ants.Free()) mem := runtime.MemStats{} runtime.ReadMemStats(&mem) @@ -303,7 +305,7 @@ func TestAntsPool(t *testing.T) { func TestPanicHandler(t *testing.T) { var panicCounter int64 var wg sync.WaitGroup - p0, err := NewPool(10, WithPanicHandler(func(p any) { + p0, err := ants.NewPool(10, ants.WithPanicHandler(func(p any) { defer wg.Done() atomic.AddInt64(&panicCounter, 1) t.Logf("catch panic with PanicHandler: %v", p) @@ -319,7 +321,7 @@ func TestPanicHandler(t *testing.T) { require.EqualValuesf(t, 1, c, "panic handler didn't work, panicCounter: %d", c) require.EqualValues(t, 0, p0.Running(), "pool should be empty after panic") - p1, err := NewPoolWithFunc(10, func(p any) { panic(p) }, WithPanicHandler(func(_ any) { + p1, err := ants.NewPoolWithFunc(10, func(p any) { panic(p) }, ants.WithPanicHandler(func(_ any) { defer wg.Done() atomic.AddInt64(&panicCounter, 1) })) @@ -332,7 +334,7 @@ func TestPanicHandler(t *testing.T) { require.EqualValuesf(t, 2, c, "panic handler didn't work, panicCounter: %d", c) require.EqualValues(t, 0, p1.Running(), "pool should be empty after panic") - p2, err := NewPoolWithFuncGeneric(10, func(s string) { panic(s) }, WithPanicHandler(func(_ any) { + p2, err := ants.NewPoolWithFuncGeneric(10, func(s string) { panic(s) }, ants.WithPanicHandler(func(_ any) { defer wg.Done() atomic.AddInt64(&panicCounter, 1) })) @@ -349,7 +351,7 @@ func TestPanicHandler(t *testing.T) { func TestPanicHandlerPreMalloc(t *testing.T) { var panicCounter int64 var wg sync.WaitGroup - p0, err := NewPool(10, WithPreAlloc(true), WithPanicHandler(func(p any) { + p0, err := ants.NewPool(10, ants.WithPreAlloc(true), ants.WithPanicHandler(func(p any) { defer wg.Done() atomic.AddInt64(&panicCounter, 1) t.Logf("catch panic with PanicHandler: %v", p) @@ -365,7 +367,7 @@ func TestPanicHandlerPreMalloc(t *testing.T) { require.EqualValuesf(t, 1, c, "panic handler didn't work, panicCounter: %d", c) require.EqualValues(t, 0, p0.Running(), "pool should be empty after panic") - p1, err := NewPoolWithFunc(10, func(p any) { panic(p) }, WithPreAlloc(true), WithPanicHandler(func(_ any) { + p1, err := ants.NewPoolWithFunc(10, func(p any) { panic(p) }, ants.WithPreAlloc(true), ants.WithPanicHandler(func(_ any) { defer wg.Done() atomic.AddInt64(&panicCounter, 1) })) @@ -378,7 +380,7 @@ func TestPanicHandlerPreMalloc(t *testing.T) { require.EqualValuesf(t, 2, c, "panic handler didn't work, panicCounter: %d", c) require.EqualValues(t, 0, p1.Running(), "pool should be empty after panic") - p2, err := NewPoolWithFuncGeneric(10, func(p string) { panic(p) }, WithPreAlloc(true), WithPanicHandler(func(_ any) { + p2, err := ants.NewPoolWithFuncGeneric(10, func(p string) { panic(p) }, ants.WithPreAlloc(true), ants.WithPanicHandler(func(_ any) { defer wg.Done() atomic.AddInt64(&panicCounter, 1) })) @@ -393,40 +395,40 @@ func TestPanicHandlerPreMalloc(t *testing.T) { } func TestPoolPanicWithoutHandler(t *testing.T) { - p0, err := NewPool(10) + p0, err := ants.NewPool(10) require.NoErrorf(t, err, "create new pool failed: %v", err) defer p0.Release() _ = p0.Submit(func() { panic("Oops!") }) - p1, err := NewPoolWithFunc(10, func(p any) { panic(p) }) + p1, err := ants.NewPoolWithFunc(10, func(p any) { panic(p) }) require.NoErrorf(t, err, "create new pool with func failed: %v", err) defer p1.Release() _ = p1.Invoke("Oops!") - p2, err := NewPoolWithFuncGeneric(10, func(p string) { panic(p) }) + p2, err := ants.NewPoolWithFuncGeneric(10, func(p string) { panic(p) }) require.NoErrorf(t, err, "create new pool with func failed: %v", err) defer p2.Release() _ = p2.Invoke("Oops!") } func TestPoolPanicWithoutHandlerPreMalloc(t *testing.T) { - p0, err := NewPool(10, WithPreAlloc(true)) + p0, err := ants.NewPool(10, ants.WithPreAlloc(true)) require.NoErrorf(t, err, "create new pool failed: %v", err) defer p0.Release() _ = p0.Submit(func() { panic("Oops!") }) - p1, err := NewPoolWithFunc(10, func(p any) { + p1, err := ants.NewPoolWithFunc(10, func(p any) { panic(p) }) require.NoErrorf(t, err, "create new pool with func failed: %v", err) defer p1.Release() _ = p1.Invoke("Oops!") - p2, err := NewPoolWithFuncGeneric(10, func(p any) { + p2, err := ants.NewPoolWithFuncGeneric(10, func(p any) { panic(p) }) require.NoErrorf(t, err, "create new pool with func failed: %v", err) @@ -438,7 +440,7 @@ func TestPurgePool(t *testing.T) { size := 500 ch := make(chan struct{}) - p, err := NewPool(size) + p, err := ants.NewPool(size) require.NoErrorf(t, err, "create TimingPool failed: %v", err) defer p.Release() @@ -450,11 +452,11 @@ func TestPurgePool(t *testing.T) { time.Sleep(time.Duration(d) * time.Millisecond) }) } - require.Equalf(t, size, p.Running(), "pool should be full, expected: %d, but got: %d", size, p.Running()) + require.EqualValuesf(t, size, p.Running(), "pool should be full, expected: %d, but got: %d", size, p.Running()) close(ch) - time.Sleep(5 * DefaultCleanIntervalTime) - require.Equalf(t, 0, p.Running(), "pool should be empty after purge, but got %d", p.Running()) + time.Sleep(5 * ants.DefaultCleanIntervalTime) + require.EqualValuesf(t, 0, p.Running(), "pool should be empty after purge, but got %d", p.Running()) ch = make(chan struct{}) f := func(i any) { @@ -463,18 +465,18 @@ func TestPurgePool(t *testing.T) { time.Sleep(time.Duration(d) * time.Millisecond) } - p1, err := NewPoolWithFunc(size, f) + p1, err := ants.NewPoolWithFunc(size, f) require.NoErrorf(t, err, "create TimingPoolWithFunc failed: %v", err) defer p1.Release() for i := 0; i < size; i++ { _ = p1.Invoke(i) } - require.Equalf(t, size, p1.Running(), "pool should be full, expected: %d, but got: %d", size, p1.Running()) + require.EqualValuesf(t, size, p1.Running(), "pool should be full, expected: %d, but got: %d", size, p1.Running()) close(ch) - time.Sleep(5 * DefaultCleanIntervalTime) - require.Equalf(t, 0, p1.Running(), "pool should be empty after purge, but got %d", p1.Running()) + time.Sleep(5 * ants.DefaultCleanIntervalTime) + require.EqualValuesf(t, 0, p1.Running(), "pool should be empty after purge, but got %d", p1.Running()) ch = make(chan struct{}) f1 := func(i int) { @@ -483,46 +485,46 @@ func TestPurgePool(t *testing.T) { time.Sleep(time.Duration(d) * time.Millisecond) } - p2, err := NewPoolWithFuncGeneric(size, f1) + p2, err := ants.NewPoolWithFuncGeneric(size, f1) require.NoErrorf(t, err, "create TimingPoolWithFunc failed: %v", err) defer p2.Release() for i := 0; i < size; i++ { _ = p2.Invoke(i) } - require.Equalf(t, size, p2.Running(), "pool should be full, expected: %d, but got: %d", size, p2.Running()) + require.EqualValuesf(t, size, p2.Running(), "pool should be full, expected: %d, but got: %d", size, p2.Running()) close(ch) - time.Sleep(5 * DefaultCleanIntervalTime) - require.Equalf(t, 0, p2.Running(), "pool should be empty after purge, but got %d", p2.Running()) + time.Sleep(5 * ants.DefaultCleanIntervalTime) + require.EqualValuesf(t, 0, p2.Running(), "pool should be empty after purge, but got %d", p2.Running()) } func TestPurgePreMallocPool(t *testing.T) { - p, err := NewPool(10, WithPreAlloc(true)) + p, err := ants.NewPool(10, ants.WithPreAlloc(true)) require.NoErrorf(t, err, "create TimingPool failed: %v", err) defer p.Release() _ = p.Submit(demoFunc) - time.Sleep(3 * DefaultCleanIntervalTime) + time.Sleep(3 * ants.DefaultCleanIntervalTime) require.EqualValues(t, 0, p.Running(), "all p should be purged") - p1, err := NewPoolWithFunc(10, demoPoolFunc) + p1, err := ants.NewPoolWithFunc(10, demoPoolFunc) require.NoErrorf(t, err, "create TimingPoolWithFunc failed: %v", err) defer p1.Release() _ = p1.Invoke(1) - time.Sleep(3 * DefaultCleanIntervalTime) + time.Sleep(3 * ants.DefaultCleanIntervalTime) require.EqualValues(t, 0, p1.Running(), "all p should be purged") - p2, err := NewPoolWithFuncGeneric(10, demoPoolFuncInt) + p2, err := ants.NewPoolWithFuncGeneric(10, demoPoolFuncInt) require.NoErrorf(t, err, "create TimingPoolWithFunc failed: %v", err) defer p2.Release() _ = p2.Invoke(1) - time.Sleep(3 * DefaultCleanIntervalTime) + time.Sleep(3 * ants.DefaultCleanIntervalTime) require.EqualValues(t, 0, p2.Running(), "all p should be purged") } func TestNonblockingSubmit(t *testing.T) { poolSize := 10 - p, err := NewPool(poolSize, WithNonblocking(true)) + p, err := ants.NewPool(poolSize, ants.WithNonblocking(true)) require.NoErrorf(t, err, "create TimingPool failed: %v", err) defer p.Release() for i := 0; i < poolSize-1; i++ { @@ -536,8 +538,8 @@ func TestNonblockingSubmit(t *testing.T) { } // p is full now. require.NoError(t, p.Submit(f), "nonblocking submit when pool is not full shouldn't return error") - require.ErrorIsf(t, p.Submit(demoFunc), ErrPoolOverload, - "nonblocking submit when pool is full should get an ErrPoolOverload") + require.ErrorIsf(t, p.Submit(demoFunc), ants.ErrPoolOverload, + "nonblocking submit when pool is full should get an ants.ErrPoolOverload") // interrupt f to get an available worker close(ch) <-ch1 @@ -546,7 +548,7 @@ func TestNonblockingSubmit(t *testing.T) { func TestMaxBlockingSubmit(t *testing.T) { poolSize := 10 - p, err := NewPool(poolSize, WithMaxBlockingTasks(1)) + p, err := ants.NewPool(poolSize, ants.WithMaxBlockingTasks(1)) require.NoErrorf(t, err, "create TimingPool failed: %v", err) defer p.Release() for i := 0; i < poolSize-1; i++ { @@ -570,8 +572,8 @@ func TestMaxBlockingSubmit(t *testing.T) { }() time.Sleep(1 * time.Second) // already reached max blocking limit - require.ErrorIsf(t, p.Submit(demoFunc), ErrPoolOverload, - "blocking submit when pool reach max blocking submit should return ErrPoolOverload") + require.ErrorIsf(t, p.Submit(demoFunc), ants.ErrPoolOverload, + "blocking submit when pool reach max blocking submit should return ants.ErrPoolOverload") // interrupt f to make blocking submit successful. close(ch) wg.Wait() @@ -586,10 +588,10 @@ func TestNonblockingSubmitWithFunc(t *testing.T) { poolSize := 10 ch := make(chan struct{}) var wg sync.WaitGroup - p, err := NewPoolWithFunc(poolSize, func(i any) { + p, err := ants.NewPoolWithFunc(poolSize, func(i any) { longRunningPoolFunc(i) wg.Done() - }, WithNonblocking(true)) + }, ants.WithNonblocking(true)) require.NoError(t, err, "create TimingPool failed: %v", err) defer p.Release() wg.Add(poolSize) @@ -598,8 +600,8 @@ func TestNonblockingSubmitWithFunc(t *testing.T) { } // p is full now. require.NoError(t, p.Invoke(ch), "nonblocking submit when pool is not full shouldn't return error") - require.ErrorIsf(t, p.Invoke(nil), ErrPoolOverload, - "nonblocking submit when pool is full should get an ErrPoolOverload") + require.ErrorIsf(t, p.Invoke(nil), ants.ErrPoolOverload, + "nonblocking submit when pool is full should get an ants.ErrPoolOverload") // interrupt f to get an available worker close(ch) wg.Wait() @@ -611,10 +613,10 @@ func TestNonblockingSubmitWithFunc(t *testing.T) { func TestNonblockingSubmitWithFuncGeneric(t *testing.T) { poolSize := 10 var wg sync.WaitGroup - p, err := NewPoolWithFuncGeneric(poolSize, func(ch chan struct{}) { + p, err := ants.NewPoolWithFuncGeneric(poolSize, func(ch chan struct{}) { longRunningPoolFuncCh(ch) wg.Done() - }, WithNonblocking(true)) + }, ants.WithNonblocking(true)) require.NoError(t, err, "create TimingPool failed: %v", err) defer p.Release() ch := make(chan struct{}) @@ -624,8 +626,8 @@ func TestNonblockingSubmitWithFuncGeneric(t *testing.T) { } // p is full now. require.NoError(t, p.Invoke(ch), "nonblocking submit when pool is not full shouldn't return error") - require.ErrorIsf(t, p.Invoke(nil), ErrPoolOverload, - "nonblocking submit when pool is full should get an ErrPoolOverload") + require.ErrorIsf(t, p.Invoke(nil), ants.ErrPoolOverload, + "nonblocking submit when pool is full should get an ants.ErrPoolOverload") // interrupt f to get an available worker close(ch) wg.Wait() @@ -637,7 +639,7 @@ func TestNonblockingSubmitWithFuncGeneric(t *testing.T) { func TestMaxBlockingSubmitWithFunc(t *testing.T) { ch := make(chan struct{}) poolSize := 10 - p, err := NewPoolWithFunc(poolSize, longRunningPoolFunc, WithMaxBlockingTasks(1)) + p, err := ants.NewPoolWithFunc(poolSize, longRunningPoolFunc, ants.WithMaxBlockingTasks(1)) require.NoError(t, err, "create TimingPool failed: %v", err) defer p.Release() for i := 0; i < poolSize-1; i++ { @@ -657,8 +659,8 @@ func TestMaxBlockingSubmitWithFunc(t *testing.T) { }() time.Sleep(1 * time.Second) // already reached max blocking limit - require.ErrorIsf(t, p.Invoke(ch), ErrPoolOverload, - "blocking submit when pool reach max blocking submit should return ErrPoolOverload: %v", err) + require.ErrorIsf(t, p.Invoke(ch), ants.ErrPoolOverload, + "blocking submit when pool reach max blocking submit should return ants.ErrPoolOverload: %v", err) // interrupt one func to make blocking submit successful. close(ch) wg.Wait() @@ -671,7 +673,7 @@ func TestMaxBlockingSubmitWithFunc(t *testing.T) { func TestMaxBlockingSubmitWithFuncGeneric(t *testing.T) { poolSize := 10 - p, err := NewPoolWithFuncGeneric(poolSize, longRunningPoolFuncCh, WithMaxBlockingTasks(1)) + p, err := ants.NewPoolWithFuncGeneric(poolSize, longRunningPoolFuncCh, ants.WithMaxBlockingTasks(1)) require.NoError(t, err, "create TimingPool failed: %v", err) defer p.Release() ch := make(chan struct{}) @@ -692,8 +694,8 @@ func TestMaxBlockingSubmitWithFuncGeneric(t *testing.T) { }() time.Sleep(1 * time.Second) // already reached max blocking limit - require.ErrorIsf(t, p.Invoke(ch), ErrPoolOverload, - "blocking submit when pool reach max blocking submit should return ErrPoolOverload: %v", err) + require.ErrorIsf(t, p.Invoke(ch), ants.ErrPoolOverload, + "blocking submit when pool reach max blocking submit should return ants.ErrPoolOverload: %v", err) // interrupt one func to make blocking submit successful. close(ch) wg.Wait() @@ -705,26 +707,26 @@ func TestMaxBlockingSubmitWithFuncGeneric(t *testing.T) { } func TestRebootDefaultPool(t *testing.T) { - defer Release() - Reboot() // should do nothing inside + defer ants.Release() + ants.Reboot() // should do nothing inside var wg sync.WaitGroup wg.Add(1) - _ = Submit(func() { + _ = ants.Submit(func() { demoFunc() wg.Done() }) wg.Wait() - require.NoError(t, ReleaseTimeout(time.Second)) - require.ErrorIsf(t, Submit(nil), ErrPoolClosed, "pool should be closed") - Reboot() + require.NoError(t, ants.ReleaseTimeout(time.Second)) + require.ErrorIsf(t, ants.Submit(nil), ants.ErrPoolClosed, "pool should be closed") + ants.Reboot() wg.Add(1) - require.NoError(t, Submit(func() { wg.Done() }), "pool should be rebooted") + require.NoError(t, ants.Submit(func() { wg.Done() }), "pool should be rebooted") wg.Wait() } func TestRebootNewPool(t *testing.T) { var wg sync.WaitGroup - p, err := NewPool(10) + p, err := ants.NewPool(10) require.NoErrorf(t, err, "create Pool failed: %v", err) defer p.Release() wg.Add(1) @@ -734,13 +736,13 @@ func TestRebootNewPool(t *testing.T) { }) wg.Wait() require.NoError(t, p.ReleaseTimeout(time.Second)) - require.ErrorIsf(t, p.Submit(nil), ErrPoolClosed, "pool should be closed") + require.ErrorIsf(t, p.Submit(nil), ants.ErrPoolClosed, "pool should be closed") p.Reboot() wg.Add(1) require.NoError(t, p.Submit(func() { wg.Done() }), "pool should be rebooted") wg.Wait() - p1, err := NewPoolWithFunc(10, func(i any) { + p1, err := ants.NewPoolWithFunc(10, func(i any) { demoPoolFunc(i) wg.Done() }) @@ -750,13 +752,13 @@ func TestRebootNewPool(t *testing.T) { _ = p1.Invoke(1) wg.Wait() require.NoError(t, p1.ReleaseTimeout(time.Second)) - require.ErrorIsf(t, p1.Invoke(nil), ErrPoolClosed, "pool should be closed") + require.ErrorIsf(t, p1.Invoke(nil), ants.ErrPoolClosed, "pool should be closed") p1.Reboot() wg.Add(1) require.NoError(t, p1.Invoke(1), "pool should be rebooted") wg.Wait() - p2, err := NewPoolWithFuncGeneric(10, func(i int) { + p2, err := ants.NewPoolWithFuncGeneric(10, func(i int) { demoPoolFuncInt(i) wg.Done() }) @@ -766,7 +768,7 @@ func TestRebootNewPool(t *testing.T) { _ = p2.Invoke(1) wg.Wait() require.NoError(t, p2.ReleaseTimeout(time.Second)) - require.ErrorIsf(t, p2.Invoke(1), ErrPoolClosed, "pool should be closed") + require.ErrorIsf(t, p2.Invoke(1), ants.ErrPoolClosed, "pool should be closed") p2.Reboot() wg.Add(1) require.NoError(t, p2.Invoke(1), "pool should be rebooted") @@ -775,7 +777,7 @@ func TestRebootNewPool(t *testing.T) { func TestInfinitePool(t *testing.T) { c := make(chan struct{}) - p, _ := NewPool(-1) + p, _ := ants.NewPool(-1) _ = p.Submit(func() { _ = p.Submit(func() { <-c @@ -793,11 +795,11 @@ func TestInfinitePool(t *testing.T) { t.Fatalf("expect capacity: -1 but got %d", capacity) } var err error - _, err = NewPool(-1, WithPreAlloc(true)) - require.EqualErrorf(t, err, ErrInvalidPreAllocSize.Error(), "") + _, err = ants.NewPool(-1, ants.WithPreAlloc(true)) + require.ErrorIs(t, err, ants.ErrInvalidPreAllocSize) } -func testPoolWithDisablePurge(t *testing.T, p *Pool, numWorker int, waitForPurge time.Duration) { +func testPoolWithDisablePurge(t *testing.T, p *ants.Pool, numWorker int, waitForPurge time.Duration) { sig := make(chan struct{}) var wg1, wg2 sync.WaitGroup wg1.Add(numWorker) @@ -838,18 +840,18 @@ func testPoolWithDisablePurge(t *testing.T, p *Pool, numWorker int, waitForPurge func TestWithDisablePurgePool(t *testing.T) { numWorker := 10 - p, _ := NewPool(numWorker, WithDisablePurge(true)) - testPoolWithDisablePurge(t, p, numWorker, DefaultCleanIntervalTime) + p, _ := ants.NewPool(numWorker, ants.WithDisablePurge(true)) + testPoolWithDisablePurge(t, p, numWorker, ants.DefaultCleanIntervalTime) } func TestWithDisablePurgeAndWithExpirationPool(t *testing.T) { numWorker := 10 expiredDuration := time.Millisecond * 100 - p, _ := NewPool(numWorker, WithDisablePurge(true), WithExpiryDuration(expiredDuration)) + p, _ := ants.NewPool(numWorker, ants.WithDisablePurge(true), ants.WithExpiryDuration(expiredDuration)) testPoolWithDisablePurge(t, p, numWorker, expiredDuration) } -func testPoolFuncWithDisablePurge(t *testing.T, p *PoolWithFunc, numWorker int, wg1, wg2 *sync.WaitGroup, sig chan struct{}, waitForPurge time.Duration) { +func testPoolFuncWithDisablePurge(t *testing.T, p *ants.PoolWithFunc, numWorker int, wg1, wg2 *sync.WaitGroup, sig chan struct{}, waitForPurge time.Duration) { for i := 0; i < numWorker; i++ { _ = p.Invoke(i) } @@ -886,12 +888,12 @@ func TestWithDisablePurgePoolFunc(t *testing.T) { var wg1, wg2 sync.WaitGroup wg1.Add(numWorker) wg2.Add(numWorker) - p, _ := NewPoolWithFunc(numWorker, func(_ any) { + p, _ := ants.NewPoolWithFunc(numWorker, func(_ any) { wg1.Done() <-sig wg2.Done() - }, WithDisablePurge(true)) - testPoolFuncWithDisablePurge(t, p, numWorker, &wg1, &wg2, sig, DefaultCleanIntervalTime) + }, ants.WithDisablePurge(true)) + testPoolFuncWithDisablePurge(t, p, numWorker, &wg1, &wg2, sig, ants.DefaultCleanIntervalTime) } func TestWithDisablePurgeAndWithExpirationPoolFunc(t *testing.T) { @@ -901,17 +903,17 @@ func TestWithDisablePurgeAndWithExpirationPoolFunc(t *testing.T) { wg1.Add(numWorker) wg2.Add(numWorker) expiredDuration := time.Millisecond * 100 - p, _ := NewPoolWithFunc(numWorker, func(_ any) { + p, _ := ants.NewPoolWithFunc(numWorker, func(_ any) { wg1.Done() <-sig wg2.Done() - }, WithDisablePurge(true), WithExpiryDuration(expiredDuration)) + }, ants.WithDisablePurge(true), ants.WithExpiryDuration(expiredDuration)) testPoolFuncWithDisablePurge(t, p, numWorker, &wg1, &wg2, sig, expiredDuration) } func TestInfinitePoolWithFunc(t *testing.T) { c := make(chan struct{}) - p, err := NewPoolWithFunc(-1, func(i any) { + p, err := ants.NewPoolWithFunc(-1, func(i any) { demoPoolFunc(i) <-c }) @@ -931,13 +933,13 @@ func TestInfinitePoolWithFunc(t *testing.T) { if capacity := p.Cap(); capacity != -1 { t.Fatalf("expect capacity: -1 but got %d", capacity) } - _, err = NewPoolWithFunc(-1, demoPoolFunc, WithPreAlloc(true)) - require.ErrorIsf(t, err, ErrInvalidPreAllocSize, "expect ErrInvalidPreAllocSize but got %v", err) + _, err = ants.NewPoolWithFunc(-1, demoPoolFunc, ants.WithPreAlloc(true)) + require.ErrorIsf(t, err, ants.ErrInvalidPreAllocSize, "expect ErrInvalidPreAllocSize but got %v", err) } func TestInfinitePoolWithFuncGeneric(t *testing.T) { c := make(chan struct{}) - p, err := NewPoolWithFuncGeneric(-1, func(i int) { + p, err := ants.NewPoolWithFuncGeneric(-1, func(i int) { demoPoolFuncInt(i) <-c }) @@ -957,13 +959,13 @@ func TestInfinitePoolWithFuncGeneric(t *testing.T) { if capacity := p.Cap(); capacity != -1 { t.Fatalf("expect capacity: -1 but got %d", capacity) } - _, err = NewPoolWithFuncGeneric(-1, demoPoolFuncInt, WithPreAlloc(true)) - require.ErrorIsf(t, err, ErrInvalidPreAllocSize, "expect ErrInvalidPreAllocSize but got %v", err) + _, err = ants.NewPoolWithFuncGeneric(-1, demoPoolFuncInt, ants.WithPreAlloc(true)) + require.ErrorIsf(t, err, ants.ErrInvalidPreAllocSize, "expect ErrInvalidPreAllocSize but got %v", err) } func TestReleaseWhenRunningPool(t *testing.T) { var wg sync.WaitGroup - p, err := NewPool(1) + p, err := ants.NewPool(1) require.NoErrorf(t, err, "create pool failed: %v", err) wg.Add(2) go func() { @@ -1004,7 +1006,7 @@ func TestReleaseWhenRunningPool(t *testing.T) { func TestReleaseWhenRunningPoolWithFunc(t *testing.T) { var wg sync.WaitGroup - p, err := NewPoolWithFunc(1, func(i any) { + p, err := ants.NewPoolWithFunc(1, func(i any) { t.Log("do task", i) time.Sleep(1 * time.Second) }) @@ -1041,7 +1043,7 @@ func TestReleaseWhenRunningPoolWithFunc(t *testing.T) { func TestReleaseWhenRunningPoolWithFuncGeneric(t *testing.T) { var wg sync.WaitGroup - p, err := NewPoolWithFuncGeneric(1, func(i int) { + p, err := ants.NewPoolWithFuncGeneric(1, func(i int) { t.Log("do task", i) time.Sleep(1 * time.Second) }) @@ -1077,32 +1079,32 @@ func TestReleaseWhenRunningPoolWithFuncGeneric(t *testing.T) { } func TestRestCodeCoverage(t *testing.T) { - _, err := NewPool(-1, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) - _, err = NewPool(1, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) - _, err = NewPoolWithFunc(-1, demoPoolFunc, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) - _, err = NewPoolWithFunc(1, demoPoolFunc, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) - _, err = NewPoolWithFunc(1, nil, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrLackPoolFunc) - _, err = NewPoolWithFuncGeneric(-1, demoPoolFuncInt, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) - _, err = NewPoolWithFuncGeneric(1, demoPoolFuncInt, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) + _, err := ants.NewPool(-1, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) + _, err = ants.NewPool(1, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) + _, err = ants.NewPoolWithFunc(-1, demoPoolFunc, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) + _, err = ants.NewPoolWithFunc(1, demoPoolFunc, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) + _, err = ants.NewPoolWithFunc(1, nil, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrLackPoolFunc) + _, err = ants.NewPoolWithFuncGeneric(-1, demoPoolFuncInt, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) + _, err = ants.NewPoolWithFuncGeneric(1, demoPoolFuncInt, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) var fn func(i int) - _, err = NewPoolWithFuncGeneric(1, fn, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrLackPoolFunc) + _, err = ants.NewPoolWithFuncGeneric(1, fn, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrLackPoolFunc) - options := Options{} + options := ants.Options{} options.ExpiryDuration = time.Duration(10) * time.Second options.Nonblocking = true options.PreAlloc = true - poolOpts, _ := NewPool(1, WithOptions(options)) + poolOpts, _ := ants.NewPool(1, ants.WithOptions(options)) t.Logf("Pool with options, capacity: %d", poolOpts.Cap()) - p0, _ := NewPool(TestSize, WithLogger(log.New(os.Stderr, "", log.LstdFlags))) + p0, _ := ants.NewPool(TestSize, ants.WithLogger(log.New(os.Stderr, "", log.LstdFlags))) defer func() { _ = p0.Submit(demoFunc) }() @@ -1117,7 +1119,7 @@ func TestRestCodeCoverage(t *testing.T) { p0.Tune(TestSize / 10) t.Logf("pool, after tuning capacity, capacity:%d, running:%d", p0.Cap(), p0.Running()) - p1, _ := NewPool(TestSize, WithPreAlloc(true)) + p1, _ := ants.NewPool(TestSize, ants.WithPreAlloc(true)) defer func() { _ = p1.Submit(demoFunc) }() @@ -1132,7 +1134,7 @@ func TestRestCodeCoverage(t *testing.T) { p1.Tune(TestSize / 10) t.Logf("pre-malloc pool, after tuning capacity, capacity:%d, running:%d", p1.Cap(), p1.Running()) - p2, _ := NewPoolWithFunc(TestSize, demoPoolFunc) + p2, _ := ants.NewPoolWithFunc(TestSize, demoPoolFunc) defer func() { _ = p2.Invoke(Param) }() @@ -1140,7 +1142,7 @@ func TestRestCodeCoverage(t *testing.T) { for i := 0; i < n; i++ { _ = p2.Invoke(Param) } - time.Sleep(DefaultCleanIntervalTime) + time.Sleep(ants.DefaultCleanIntervalTime) t.Logf("pool with func, capacity:%d", p2.Cap()) t.Logf("pool with func, running workers number:%d", p2.Running()) t.Logf("pool with func, free workers number:%d", p2.Free()) @@ -1148,7 +1150,7 @@ func TestRestCodeCoverage(t *testing.T) { p2.Tune(TestSize / 10) t.Logf("pool with func, after tuning capacity, capacity:%d, running:%d", p2.Cap(), p2.Running()) - p3, _ := NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt) + p3, _ := ants.NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt) defer func() { _ = p3.Invoke(Param) }() @@ -1156,7 +1158,7 @@ func TestRestCodeCoverage(t *testing.T) { for i := 0; i < n; i++ { _ = p3.Invoke(Param) } - time.Sleep(DefaultCleanIntervalTime) + time.Sleep(ants.DefaultCleanIntervalTime) t.Logf("pool with func, capacity:%d", p3.Cap()) t.Logf("pool with func, running workers number:%d", p3.Running()) t.Logf("pool with func, free workers number:%d", p3.Free()) @@ -1164,7 +1166,7 @@ func TestRestCodeCoverage(t *testing.T) { p3.Tune(TestSize / 10) t.Logf("pool with func, after tuning capacity, capacity:%d, running:%d", p3.Cap(), p3.Running()) - p4, _ := NewPoolWithFunc(TestSize, demoPoolFunc, WithPreAlloc(true)) + p4, _ := ants.NewPoolWithFunc(TestSize, demoPoolFunc, ants.WithPreAlloc(true)) defer func() { _ = p4.Invoke(Param) }() @@ -1172,7 +1174,7 @@ func TestRestCodeCoverage(t *testing.T) { for i := 0; i < n; i++ { _ = p4.Invoke(Param) } - time.Sleep(DefaultCleanIntervalTime) + time.Sleep(ants.DefaultCleanIntervalTime) t.Logf("pre-malloc pool with func, capacity:%d", p4.Cap()) t.Logf("pre-malloc pool with func, running workers number:%d", p4.Running()) t.Logf("pre-malloc pool with func, free workers number:%d", p4.Free()) @@ -1181,7 +1183,7 @@ func TestRestCodeCoverage(t *testing.T) { t.Logf("pre-malloc pool with func, after tuning capacity, capacity:%d, running:%d", p4.Cap(), p4.Running()) - p5, _ := NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt, WithPreAlloc(true)) + p5, _ := ants.NewPoolWithFuncGeneric(TestSize, demoPoolFuncInt, ants.WithPreAlloc(true)) defer func() { _ = p5.Invoke(Param) }() @@ -1189,7 +1191,7 @@ func TestRestCodeCoverage(t *testing.T) { for i := 0; i < n; i++ { _ = p5.Invoke(Param) } - time.Sleep(DefaultCleanIntervalTime) + time.Sleep(ants.DefaultCleanIntervalTime) t.Logf("pre-malloc pool with func, capacity:%d", p5.Cap()) t.Logf("pre-malloc pool with func, running workers number:%d", p5.Running()) t.Logf("pre-malloc pool with func, free workers number:%d", p5.Free()) @@ -1202,7 +1204,7 @@ func TestRestCodeCoverage(t *testing.T) { func TestPoolTuneScaleUp(t *testing.T) { c := make(chan struct{}) // Test Pool - p, _ := NewPool(2) + p, _ := ants.NewPool(2) for i := 0; i < 2; i++ { _ = p.Submit(func() { <-c @@ -1238,7 +1240,7 @@ func TestPoolTuneScaleUp(t *testing.T) { p.Release() // Test PoolWithFunc - pf, _ := NewPoolWithFunc(2, func(_ any) { + pf, _ := ants.NewPoolWithFunc(2, func(_ any) { <-c }) for i := 0; i < 2; i++ { @@ -1269,7 +1271,7 @@ func TestPoolTuneScaleUp(t *testing.T) { pf.Release() // Test PoolWithFuncGeneric - pfg, _ := NewPoolWithFuncGeneric(2, func(_ int) { + pfg, _ := ants.NewPoolWithFuncGeneric(2, func(_ int) { <-c }) for i := 0; i < 2; i++ { @@ -1302,7 +1304,7 @@ func TestPoolTuneScaleUp(t *testing.T) { } func TestReleaseTimeout(t *testing.T) { - p, err := NewPool(10) + p, err := ants.NewPool(10) require.NoError(t, err) for i := 0; i < 5; i++ { _ = p.Submit(func() { @@ -1313,7 +1315,7 @@ func TestReleaseTimeout(t *testing.T) { err = p.ReleaseTimeout(2 * time.Second) require.NoError(t, err) - pf, err := NewPoolWithFunc(10, func(i any) { + pf, err := ants.NewPoolWithFunc(10, func(i any) { dur := i.(time.Duration) time.Sleep(dur) }) @@ -1325,7 +1327,7 @@ func TestReleaseTimeout(t *testing.T) { err = pf.ReleaseTimeout(2 * time.Second) require.NoError(t, err) - pfg, err := NewPoolWithFuncGeneric(10, func(d time.Duration) { + pfg, err := ants.NewPoolWithFuncGeneric(10, func(d time.Duration) { time.Sleep(d) }) require.NoError(t, err) @@ -1338,26 +1340,26 @@ func TestReleaseTimeout(t *testing.T) { } func TestDefaultPoolReleaseTimeout(t *testing.T) { - Reboot() // should do nothing inside + ants.Reboot() // should do nothing inside for i := 0; i < 5; i++ { - _ = Submit(func() { + _ = ants.Submit(func() { time.Sleep(time.Second) }) } - require.NotZero(t, Running()) - err := ReleaseTimeout(2 * time.Second) + require.NotZero(t, ants.Running()) + err := ants.ReleaseTimeout(2 * time.Second) require.NoError(t, err) } func TestMultiPool(t *testing.T) { - _, err := NewMultiPool(-1, 10, 8) - require.ErrorIs(t, err, ErrInvalidMultiPoolSize) - _, err = NewMultiPool(10, -1, 8) - require.ErrorIs(t, err, ErrInvalidLoadBalancingStrategy) - _, err = NewMultiPool(10, 10, RoundRobin, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) - - mp, err := NewMultiPool(10, 5, RoundRobin) + _, err := ants.NewMultiPool(-1, 10, 8) + require.ErrorIs(t, err, ants.ErrInvalidMultiPoolSize) + _, err = ants.NewMultiPool(10, -1, 8) + require.ErrorIs(t, err, ants.ErrInvalidLoadBalancingStrategy) + _, err = ants.NewMultiPool(10, 10, ants.RoundRobin, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) + + mp, err := ants.NewMultiPool(10, 5, ants.RoundRobin) testFn := func() { for i := 0; i < 50; i++ { err = mp.Submit(longRunningFunc) @@ -1365,19 +1367,19 @@ func TestMultiPool(t *testing.T) { } require.EqualValues(t, mp.Waiting(), 0) _, err = mp.WaitingByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.WaitingByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 50, mp.Running()) _, err = mp.RunningByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.RunningByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 0, mp.Free()) _, err = mp.FreeByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.FreeByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 50, mp.Cap()) require.False(t, mp.IsClosed()) for i := 0; i < 10; i++ { @@ -1390,8 +1392,8 @@ func TestMultiPool(t *testing.T) { } atomic.StoreInt32(&stopLongRunningFunc, 1) require.NoError(t, mp.ReleaseTimeout(3*time.Second)) - require.ErrorIs(t, mp.ReleaseTimeout(3*time.Second), ErrPoolClosed) - require.ErrorIs(t, mp.Submit(nil), ErrPoolClosed) + require.ErrorIs(t, mp.ReleaseTimeout(3*time.Second), ants.ErrPoolClosed) + require.ErrorIs(t, mp.Submit(nil), ants.ErrPoolClosed) require.Zero(t, mp.Running()) require.True(t, mp.IsClosed()) atomic.StoreInt32(&stopLongRunningFunc, 0) @@ -1401,7 +1403,7 @@ func TestMultiPool(t *testing.T) { mp.Reboot() testFn() - mp, err = NewMultiPool(10, 5, LeastTasks) + mp, err = ants.NewMultiPool(10, 5, ants.LeastTasks) testFn() mp.Reboot() @@ -1411,15 +1413,15 @@ func TestMultiPool(t *testing.T) { } func TestMultiPoolWithFunc(t *testing.T) { - _, err := NewMultiPoolWithFunc(-1, 10, longRunningPoolFunc, 8) - require.ErrorIs(t, err, ErrInvalidMultiPoolSize) - _, err = NewMultiPoolWithFunc(10, -1, longRunningPoolFunc, 8) - require.ErrorIs(t, err, ErrInvalidLoadBalancingStrategy) - _, err = NewMultiPoolWithFunc(10, 10, longRunningPoolFunc, RoundRobin, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) + _, err := ants.NewMultiPoolWithFunc(-1, 10, longRunningPoolFunc, 8) + require.ErrorIs(t, err, ants.ErrInvalidMultiPoolSize) + _, err = ants.NewMultiPoolWithFunc(10, -1, longRunningPoolFunc, 8) + require.ErrorIs(t, err, ants.ErrInvalidLoadBalancingStrategy) + _, err = ants.NewMultiPoolWithFunc(10, 10, longRunningPoolFunc, ants.RoundRobin, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) ch := make(chan struct{}) - mp, err := NewMultiPoolWithFunc(10, 5, longRunningPoolFunc, RoundRobin) + mp, err := ants.NewMultiPoolWithFunc(10, 5, longRunningPoolFunc, ants.RoundRobin) testFn := func() { for i := 0; i < 50; i++ { err = mp.Invoke(ch) @@ -1427,19 +1429,19 @@ func TestMultiPoolWithFunc(t *testing.T) { } require.EqualValues(t, mp.Waiting(), 0) _, err = mp.WaitingByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.WaitingByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 50, mp.Running()) _, err = mp.RunningByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.RunningByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 0, mp.Free()) _, err = mp.FreeByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.FreeByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 50, mp.Cap()) require.False(t, mp.IsClosed()) for i := 0; i < 10; i++ { @@ -1452,8 +1454,8 @@ func TestMultiPoolWithFunc(t *testing.T) { } close(ch) require.NoError(t, mp.ReleaseTimeout(3*time.Second)) - require.ErrorIs(t, mp.ReleaseTimeout(3*time.Second), ErrPoolClosed) - require.ErrorIs(t, mp.Invoke(nil), ErrPoolClosed) + require.ErrorIs(t, mp.ReleaseTimeout(3*time.Second), ants.ErrPoolClosed) + require.ErrorIs(t, mp.Invoke(nil), ants.ErrPoolClosed) require.Zero(t, mp.Running()) require.True(t, mp.IsClosed()) ch = make(chan struct{}) @@ -1463,7 +1465,7 @@ func TestMultiPoolWithFunc(t *testing.T) { mp.Reboot() testFn() - mp, err = NewMultiPoolWithFunc(10, 5, longRunningPoolFunc, LeastTasks) + mp, err = ants.NewMultiPoolWithFunc(10, 5, longRunningPoolFunc, ants.LeastTasks) testFn() mp.Reboot() @@ -1473,15 +1475,15 @@ func TestMultiPoolWithFunc(t *testing.T) { } func TestMultiPoolWithFuncGeneric(t *testing.T) { - _, err := NewMultiPoolWithFuncGeneric(-1, 10, longRunningPoolFuncCh, 8) - require.ErrorIs(t, err, ErrInvalidMultiPoolSize) - _, err = NewMultiPoolWithFuncGeneric(10, -1, longRunningPoolFuncCh, 8) - require.ErrorIs(t, err, ErrInvalidLoadBalancingStrategy) - _, err = NewMultiPoolWithFuncGeneric(10, 10, longRunningPoolFuncCh, RoundRobin, WithExpiryDuration(-1)) - require.ErrorIs(t, err, ErrInvalidPoolExpiry) + _, err := ants.NewMultiPoolWithFuncGeneric(-1, 10, longRunningPoolFuncCh, 8) + require.ErrorIs(t, err, ants.ErrInvalidMultiPoolSize) + _, err = ants.NewMultiPoolWithFuncGeneric(10, -1, longRunningPoolFuncCh, 8) + require.ErrorIs(t, err, ants.ErrInvalidLoadBalancingStrategy) + _, err = ants.NewMultiPoolWithFuncGeneric(10, 10, longRunningPoolFuncCh, ants.RoundRobin, ants.WithExpiryDuration(-1)) + require.ErrorIs(t, err, ants.ErrInvalidPoolExpiry) ch := make(chan struct{}) - mp, err := NewMultiPoolWithFuncGeneric(10, 5, longRunningPoolFuncCh, RoundRobin) + mp, err := ants.NewMultiPoolWithFuncGeneric(10, 5, longRunningPoolFuncCh, ants.RoundRobin) testFn := func() { for i := 0; i < 50; i++ { err = mp.Invoke(ch) @@ -1489,19 +1491,19 @@ func TestMultiPoolWithFuncGeneric(t *testing.T) { } require.EqualValues(t, mp.Waiting(), 0) _, err = mp.WaitingByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.WaitingByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 50, mp.Running()) _, err = mp.RunningByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.RunningByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 0, mp.Free()) _, err = mp.FreeByIndex(-1) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) _, err = mp.FreeByIndex(11) - require.ErrorIs(t, err, ErrInvalidPoolIndex) + require.ErrorIs(t, err, ants.ErrInvalidPoolIndex) require.EqualValues(t, 50, mp.Cap()) require.False(t, mp.IsClosed()) for i := 0; i < 10; i++ { @@ -1514,8 +1516,8 @@ func TestMultiPoolWithFuncGeneric(t *testing.T) { } close(ch) require.NoError(t, mp.ReleaseTimeout(3*time.Second)) - require.ErrorIs(t, mp.ReleaseTimeout(3*time.Second), ErrPoolClosed) - require.ErrorIs(t, mp.Invoke(nil), ErrPoolClosed) + require.ErrorIs(t, mp.ReleaseTimeout(3*time.Second), ants.ErrPoolClosed) + require.ErrorIs(t, mp.Invoke(nil), ants.ErrPoolClosed) require.Zero(t, mp.Running()) require.True(t, mp.IsClosed()) ch = make(chan struct{}) @@ -1525,7 +1527,7 @@ func TestMultiPoolWithFuncGeneric(t *testing.T) { mp.Reboot() testFn() - mp, err = NewMultiPoolWithFuncGeneric(10, 5, longRunningPoolFuncCh, LeastTasks) + mp, err = ants.NewMultiPoolWithFuncGeneric(10, 5, longRunningPoolFuncCh, ants.LeastTasks) testFn() mp.Reboot() diff --git a/example_test.go b/example_test.go new file mode 100644 index 0000000..56c8645 --- /dev/null +++ b/example_test.go @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2025. Andy Pan. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package ants_test + +import ( + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/panjf2000/ants/v2" +) + +var ( + sum int32 + wg sync.WaitGroup +) + +func incSum(i any) { + incSumInt(i.(int32)) +} + +func incSumInt(i int32) { + atomic.AddInt32(&sum, i) + wg.Done() +} + +func ExamplePool() { + ants.Reboot() // ensure the default pool is available + + atomic.StoreInt32(&sum, 0) + runTimes := 1000 + wg.Add(runTimes) + // Use the default pool. + for i := 0; i < runTimes; i++ { + j := i + _ = ants.Submit(func() { + incSumInt(int32(j)) + }) + } + wg.Wait() + fmt.Printf("The result is %d\n", sum) + + atomic.StoreInt32(&sum, 0) + wg.Add(runTimes) + // Use the new pool. + pool, _ := ants.NewPool(10) + defer pool.Release() + for i := 0; i < runTimes; i++ { + j := i + _ = pool.Submit(func() { + incSumInt(int32(j)) + }) + } + wg.Wait() + fmt.Printf("The result is %d\n", sum) + + // Output: + // The result is 499500 + // The result is 499500 +} + +func ExamplePoolWithFunc() { + atomic.StoreInt32(&sum, 0) + runTimes := 1000 + wg.Add(runTimes) + + pool, _ := ants.NewPoolWithFunc(10, incSum) + defer pool.Release() + + for i := 0; i < runTimes; i++ { + _ = pool.Invoke(int32(i)) + } + wg.Wait() + + fmt.Printf("The result is %d\n", sum) + + // Output: The result is 499500 +} + +func ExamplePoolWithFuncGeneric() { + atomic.StoreInt32(&sum, 0) + runTimes := 1000 + wg.Add(runTimes) + + pool, _ := ants.NewPoolWithFuncGeneric(10, incSumInt) + defer pool.Release() + + for i := 0; i < runTimes; i++ { + _ = pool.Invoke(int32(i)) + } + wg.Wait() + + fmt.Printf("The result is %d\n", sum) + + // Output: The result is 499500 +} + +func ExampleMultiPool() { + atomic.StoreInt32(&sum, 0) + runTimes := 1000 + wg.Add(runTimes) + + mp, _ := ants.NewMultiPool(10, runTimes/10, ants.RoundRobin) + defer mp.ReleaseTimeout(time.Second) // nolint:errcheck + + for i := 0; i < runTimes; i++ { + j := i + _ = mp.Submit(func() { + incSumInt(int32(j)) + }) + } + wg.Wait() + + fmt.Printf("The result is %d\n", sum) + + // Output: The result is 499500 +} + +func ExampleMultiPoolWithFunc() { + atomic.StoreInt32(&sum, 0) + runTimes := 1000 + wg.Add(runTimes) + + mp, _ := ants.NewMultiPoolWithFunc(10, runTimes/10, incSum, ants.RoundRobin) + defer mp.ReleaseTimeout(time.Second) // nolint:errcheck + + for i := 0; i < runTimes; i++ { + _ = mp.Invoke(int32(i)) + } + wg.Wait() + + fmt.Printf("The result is %d\n", sum) + + // Output: The result is 499500 +} + +func ExampleMultiPoolWithFuncGeneric() { + atomic.StoreInt32(&sum, 0) + runTimes := 1000 + wg.Add(runTimes) + + mp, _ := ants.NewMultiPoolWithFuncGeneric(10, runTimes/10, incSumInt, ants.RoundRobin) + defer mp.ReleaseTimeout(time.Second) // nolint:errcheck + + for i := 0; i < runTimes; i++ { + _ = mp.Invoke(int32(i)) + } + wg.Wait() + + fmt.Printf("The result is %d\n", sum) + + // Output: The result is 499500 +} diff --git a/examples/main.go b/examples/main.go deleted file mode 100644 index bc00ef8..0000000 --- a/examples/main.go +++ /dev/null @@ -1,114 +0,0 @@ -// MIT License - -// Copyright (c) 2018 Andy Pan - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -package main - -import ( - "fmt" - "sync" - "sync/atomic" - "time" - - "github.com/panjf2000/ants/v2" -) - -var sum int32 - -func myFunc(i any) { - n := i.(int32) - atomic.AddInt32(&sum, n) - fmt.Printf("run with %d\n", n) -} - -func demoFunc() { - time.Sleep(10 * time.Millisecond) - fmt.Println("Hello World!") -} - -func main() { - defer ants.Release() - - runTimes := 1000 - - // Use the common pool. - var wg sync.WaitGroup - syncCalculateSum := func() { - demoFunc() - wg.Done() - } - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = ants.Submit(syncCalculateSum) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", ants.Running()) - fmt.Printf("finish all tasks.\n") - - // Use the pool with a function, - // set 10 to the capacity of goroutine pool and 1 second for expired duration. - p, _ := ants.NewPoolWithFunc(10, func(i any) { - myFunc(i) - wg.Done() - }) - defer p.Release() - // Submit tasks one by one. - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = p.Invoke(int32(i)) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", p.Running()) - fmt.Printf("finish all tasks, result is %d\n", sum) - if sum != 499500 { - panic("the final result is wrong!!!") - } - - // Use the MultiPool and set the capacity of the 10 goroutine pools to unlimited. - // If you use -1 as the pool size parameter, the size will be unlimited. - // There are two load-balancing algorithms for pools: ants.RoundRobin and ants.LeastTasks. - mp, _ := ants.NewMultiPool(10, -1, ants.RoundRobin) - defer mp.ReleaseTimeout(5 * time.Second) - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = mp.Submit(syncCalculateSum) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", mp.Running()) - fmt.Printf("finish all tasks.\n") - - // Use the MultiPoolFunc and set the capacity of 10 goroutine pools to (runTimes/10). - mpf, _ := ants.NewMultiPoolWithFunc(10, runTimes/10, func(i any) { - myFunc(i) - wg.Done() - }, ants.LeastTasks) - defer mpf.ReleaseTimeout(5 * time.Second) - for i := 0; i < runTimes; i++ { - wg.Add(1) - _ = mpf.Invoke(int32(i)) - } - wg.Wait() - fmt.Printf("running goroutines: %d\n", mpf.Running()) - fmt.Printf("finish all tasks, result is %d\n", sum) - if sum != 499500*2 { - panic("the final result is wrong!!!") - } -} diff --git a/options.go b/options.go index b859bef..182cd5a 100644 --- a/options.go +++ b/options.go @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2018. Andy Pan. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package ants import "time" diff --git a/worker_loop_queue.go b/worker_loop_queue.go index 52091f3..b372983 100644 --- a/worker_loop_queue.go +++ b/worker_loop_queue.go @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019. Ants Authors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package ants import "time" diff --git a/worker_loop_queue_test.go b/worker_loop_queue_test.go index 8e04394..83074dd 100644 --- a/worker_loop_queue_test.go +++ b/worker_loop_queue_test.go @@ -1,8 +1,29 @@ -//go:build !windows +/* + * Copyright (c) 2019. Ants Authors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package ants import ( + "runtime" "testing" "time" @@ -51,6 +72,10 @@ func TestLoopQueue(t *testing.T) { } func TestRotatedQueueSearch(t *testing.T) { + if runtime.GOOS == "windows" { // time.Now() doesn't seem to be precise on Windows + t.Skip("Skip this test on Windows platform") + } + size := 10 q := newWorkerLoopQueue(size) diff --git a/worker_queue.go b/worker_queue.go index 4131972..948bc91 100644 --- a/worker_queue.go +++ b/worker_queue.go @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019. Ants Authors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package ants import ( diff --git a/worker_stack.go b/worker_stack.go index 8eb12ab..18dcd23 100644 --- a/worker_stack.go +++ b/worker_stack.go @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019. Ants Authors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package ants import "time" diff --git a/worker_stack_test.go b/worker_stack_test.go index 87fca0d..410bf57 100644 --- a/worker_stack_test.go +++ b/worker_stack_test.go @@ -1,8 +1,29 @@ -//go:build !windows +/* + * Copyright (c) 2019. Ants Authors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package ants import ( + "runtime" "testing" "time" @@ -51,6 +72,10 @@ func TestWorkerStack(t *testing.T) { // It seems that something wrong with time.Now() on Windows, not sure whether it is a bug on Windows, // so exclude this test from Windows platform temporarily. func TestSearch(t *testing.T) { + if runtime.GOOS == "windows" { // time.Now() doesn't seem to be precise on Windows + t.Skip("Skip this test on Windows platform") + } + q := newWorkerStack(0) // 1