GithubHelp home page GithubHelp logo

panjf2000 / ants Goto Github PK

View Code? Open in Web Editor NEW
12.5K 171.0 1.3K 1.83 MB

🐜🐜🐜 ants is the most powerful and reliable pooling solution for Go.

Home Page: https://ants.andypan.me/

License: MIT License

Go 100.00%
goroutine-pool goroutine pool go worker-pool ants

ants's Introduction

A goroutine pool for Go


English | 中文

📖 Introduction

Library ants implements a goroutine pool with fixed capacity, managing and recycling a massive number of goroutines, allowing developers to limit the number of goroutines in your concurrent programs.

🚀 Features:

  • Managing and recycling a massive number of goroutines automatically
  • 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
  • Handle panic gracefully to prevent programs from crash
  • Efficient in memory usage and it even achieves higher performance than unlimited goroutines in Golang
  • Nonblocking mechanism

💡 How ants works

Flow Diagram

ants-flowchart-en

Activity Diagrams

🧰 How to install

For ants v1

go get -u github.com/panjf2000/ants

For ants v2 (with GO111MODULE=on)

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:

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/panjf2000/ants/v2"
)

var sum int32

func myFunc(i interface{}) {
	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 interface{}) {
		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 interface{}) {
		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

// 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(interface{})

	// 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(interface{})) 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.Optionscontains 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/NewPoolWithFuncmethod.

Customize limited pool

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:

p, _ := ants.NewPool(10000)

Submit tasks

Tasks can be submitted by calling ants.Submit(func())

ants.Submit(func(){})

Tune pool capacity in runtime

You can tune the capacity of ants pool in runtime with Tune(int):

pool.Tune(1000) // Tune its capacity to 1000
pool.Tune(100000) // Tune its capacity to 100000

Don't worry about the contention problems in this case, the method here is thread-safe (or should be called goroutine-safe).

Pre-malloc goroutine queue in pool

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.

// ants will pre-malloc the whole capacity of pool when you invoke this method
p, _ := ants.NewPool(100000, ants.WithPreAlloc(true))

Release Pool

pool.Release()

Reboot Pool

// A pool that has been released can be still used once you invoke the Reboot().
pool.Reboot()

⚙️ About sequence

All tasks submitted to ants pool will not be guaranteed to be addressed in order, because those tasks scatter among a series of concurrent workers, thus those tasks would be executed concurrently.

👏 Contributors

Please read our Contributing Guidelines before opening a PR and thank you to all the developers who already made contributions to ants!

📄 License

The source code in ants is available under the MIT License.

📚 Relevant Articles

🖥 Use cases

business companies

The following companies/organizations use ants in production.

If your company is also using ants in production, please help us enrich this list by opening a pull request.

open-source software

The open-source projects below do concurrent programming with the help of ants.

  • gnet: A high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go.
  • milvus: An open-source vector database for scalable similarity search and AI applications.
  • nps: A lightweight, high-performance, powerful intranet penetration proxy server, with a powerful web management terminal.
  • siyuan: SiYuan is a local-first personal knowledge management system that supports complete offline use, as well as end-to-end encrypted synchronization.
  • osmedeus: A Workflow Engine for Offensive Security.
  • jitsu: An open-source Segment alternative. Fully-scriptable data ingestion engine for modern data teams. Set-up a real-time data pipeline in minutes, not days.
  • triangula: Generate high-quality triangulated and polygonal art from images.
  • teler: Real-time HTTP Intrusion Detection.
  • bsc: A Binance Smart Chain client based on the go-ethereum fork.
  • jaeles: The Swiss Army knife for automated Web Application Testing.
  • devlake: The open-source dev data platform & dashboard for your DevOps tools.
  • matrixone: MatrixOne is a future-oriented hyper-converged cloud and edge native DBMS that supports transactional, analytical, and streaming workloads with a simplified and distributed database engine, across multiple data centers, clouds, edges and other heterogeneous infrastructures.
  • bk-bcs: BlueKing Container Service (BCS, same below) is a container management and orchestration platform for the micro-services under the BlueKing ecosystem.
  • trueblocks-core: TrueBlocks improves access to blockchain data for any EVM-compatible chain (particularly Ethereum mainnet) while remaining entirely local.
  • openGemini: openGemini is an open-source,cloud-native time-series database(TSDB) that can be widely used in IoT, Internet of Vehicles(IoV), O&M monitoring, and industrial Internet scenarios.
  • AdGuardDNS: AdGuard DNS is an alternative solution for tracker blocking, privacy protection, and parental control.
  • WatchAD2.0: WatchAD2.0 是 360 信息安全中心开发的一款针对域安全的日志分析与监控系统,它可以收集所有域控上的事件日志、网络流量,通过特征匹配、协议分析、历史行为、敏感操作和蜜罐账户等方式来检测各种已知与未知威胁,功能覆盖了大部分目前的常见内网域渗透手法。
  • vanus: Vanus is a Serverless, event streaming system with processing capabilities. It easily connects SaaS, Cloud Services, and Databases to help users build next-gen Event-driven Applications.
  • trpc-go: A pluggable, high-performance RPC framework written in Golang.
  • motan-go: a remote procedure call (RPC) framework for the rapid development of high-performance distributed services.

All use cases:

If you have ants integrated into projects, feel free to open a pull request refreshing this list of use cases.

🔋 JetBrains OS licenses

ants had been being developed with GoLand under the free JetBrains Open Source license(s) granted by JetBrains s.r.o., hence I would like to express my thanks here.

💰 Backers

Support us with a monthly donation and help us continue our activities.

💎 Sponsors

Become a bronze sponsor with a monthly donation of $10 and get your logo on our README on GitHub.

☕️ Buy me a coffee

Please be sure to leave your name, GitHub account, or other social media accounts when you donate by the following means so that I can add it to the list of donors as a token of my appreciation.

        

💵 Patrons

Patrick Othmer Jimmy ChenZhen Mai Yang 王开帅 Unger Alejandro Weng Wei

🔋 Sponsorship

ants's People

Contributors

akshaynanavare avatar anteoy avatar appleboy avatar automano avatar barryz avatar bright2227 avatar callthingsoff avatar choleraehyq avatar czs007 avatar egonelbre avatar elchem avatar fanlongteng avatar glebradchenko avatar ioworker0 avatar jdamick avatar kevinbaisg avatar lam2003 avatar lilien1010 avatar liyonglion avatar panjf2000 avatar piaodazhu avatar poabob avatar sarathsp06 avatar simepel avatar thinkgos avatar twin avatar wreulicke avatar zqkgo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ants's Issues

worker exit on panic

个人认为PanicHandler设计不妥。
1.无PanicHandler时,抛出给外面的不是panic,外层感受不到。
2.无论有没有PanicHandler,都会导致worker退出,最终pool阻塞住全部任务。

Important announcement about <ants> from author !!!

Dear users of ants:
I am apologetically telling you that I have to dump all tags which already presents in ants repository.

The reason why I'm doing so is to standardize the version management with Semantic Versioning, which will make a formal and clear dependency management in go, for go modules, godep, or glide, etc. So I decide to start over the tag sequence, you could find more details in Semantic Versioning and Semantic Import Versioning, related issue: #32, #33 (very thankful to @jjeffcaii and @zplzpl who provided the suggestions about it).

I ought to apologize for the bothers brought by this change, the arch-criminal who leads to this issue would be my lack of concept about Semantic Versioning, I will spend more times learning the knowledge afterwards.

Once again, sorry for your costs in this change and thanks for your support to ants!

Have fun!

Best regards,
Andy Pan

关于优雅退出的问题

关于这个package优雅退出的问题,我看了一下Release的代码:

// Release Closed this pool. func (p *PoolWithFunc) Release() error { p.once.Do(func() { p.release <- sig{} p.lock.Lock() idleWorkers := p.workers for i, w := range idleWorkers { w.args <- nil idleWorkers[i] = nil } p.workers = nil p.lock.Unlock() }) return nil }

release中,好像没有去等待那些已经正在工作的worker处理完它们的工作?
仅仅是回收了空闲的worker

那么在收到程序退出的信号时候,release是不能确保正在工作的worker能妥善完成工作

如果想实现比较好退出方式目前好像是:

ReSize(0)

不知道我理解的对不对?

清理过期协程报错

你好,非常感谢提供这么好用的工具包。我在使用ants时,发现报异常。结果见下图
image
日志是我在periodicallyPurge里加的调试信息
image

原因分析

我认为可能原因是没有处理n==0的情况

if n > 0 {
	n++
	p.workers = idleWorkers[n:]
}

测试代码

package main

import (
	"github.com/panjf2000/ants"
	"fmt"
	"time"
	"strconv"
)

func main() {

	pool,err := ants.NewPool(100000)

	if err != nil {
		panic(err)
	}

	for i:=0;i<10000;i++{
		pool.Submit(
			func() error {
				time.Sleep(1 * time.Millisecond)
				fmt.Println(strconv.Itoa(i))
				return nil
			})
	}

	for{
		pool.Submit(
			func() error {
				time.Sleep(10 * time.Millisecond)
			return nil
		})
		time.Sleep(1 * time.Millisecond)
	}
}

是否可以添加SubmitQueue类似的接口

现在submit的任务执行顺序可以认为是随机的,但是有应用的情况是处理数据时有顺序关系,用户可以用队列来处理此类任务,但是每个task handler中都增加了队列的代码,感觉还是有点累赘。

如果ants有SumbitQueue(queueName interface{}, task func())error 这样的接口,则使用起来感觉方便很多

worker的task问题

我初略的看了一下启动的过程,有几个疑问想请教一下
在newpool之后,想要执行任务需要调用pool的submit。在submit里面,有一段代码是w.task <- task.
w是worker的意思,但worker的task chan长度只有1,所以有并发任务来的时候,都在抢占这个w.task。要怎么保证任务的先后顺序的?

关于retrieveWorker中一小段代码的疑问

if n >= 0 {
		w = idleWorkers[n]
		idleWorkers[n] = nil
		p.workers = idleWorkers[:n]
		p.lock.Unlock()
	} else if p.Running() < p.Cap() {
		p.lock.Unlock()
		spawnWorker()
	} else {
		if p.nonblocking {
			p.lock.Unlock()
			return nil
		}

if p.Running() < p.Cap() 判断以后符合条件解锁,再重新创建worker,worker会在run的时候才进行running数的加1会不会有worker在run的时候让出cpu,此时另一个协程执行到p.Running() < p.Cap()判断也符合,从而导致最终的running其实是大于cap的情况呢

1.3.0 是不兼容更新

Pool 里那些暴露出来的字段(PanicHandler 之类的)都没了,这是一个不兼容更新,根据语义化版本的要求要发大版本。

死锁bug

func (p *Pool) getWorker() *Worker 这个函数的 199行
必须先解锁在加锁, 要不然会产生死锁

p.lock.Unlock()
	<-p.freeSignal
	p.lock.Lock()

提两个小需求

  1. 在批量提交任务后,获取每个任务对应的返回值.
  2. 在批量提交任务时,可以携带一个超时参数,表示这批任务执行时,如果超时,则已执行的任务正常返回执行结果,未执行的任务都提前结束(或也返回执行结果,但是标明是timeout)。

提交任务不阻塞

Pool.SubmitPoolWithFunc.Server提交任务,如果没有空的worker,会一直阻塞。建议增加不阻塞的接口,当前失败时直接返回错误。

use example errors

./antstest.go:37:14: cannot use syncCalculateSum (type func()) as type ants.f in argument to ants.Submit
./antstest.go:45:35: cannot use func literal (type func(interface {})) as type ants.pf in argument to ants.NewPoolWithFunc

潘少,更新下tag吧

鄙人现在在弄dep依赖管理,有用到你写的ants项目,可是你好像忘记打最新的tag了。最新的tag 3.6是指向ed55924这个提交,git上的最新代码是af376f1b这次提交,两次提交都隔了快5个月了,看到的话,麻烦打一个最新的tag吧。(手动可怜)

非阻塞在PoolOverload时进入等待队列

Is your feature request related to a problem? Please describe.
submit的函数如果是递归函数,则如果是阻塞模式,在递归深度较大的时候,会因为worker用光,程序直接被阻塞了,如果调整为非阻塞模式,则会在worker用光之后,后面的任务直接返回ErrPoolOverload而被舍弃。我是在遍历目录的时候遇到的这个问题。

Describe the solution you'd like
增加一个配置项,非阻塞模式下,可以选择增加一个等待队列,而不是舍弃。

Describe alternatives you've considered
增加一个channel,用于task完成后通知等待队列

函数执行保护

func (w *Worker) run() {
	//atomic.AddInt32(&w.pool.running, 1)
	go func() {
		for f := range w.task {
			if f == nil {
				atomic.AddInt32(&w.pool.running, -1)
				return
			}
			f()//直接执行了
			w.pool.putWorker(w)
		}
	}()
}

那么会不会出现f执行错误崩溃的情况?
加个执行保护不知道行不行。。。新手。

增加调试功能

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
有时任务发生问题,一直不结束或任务太多, 想知道是哪些任务

Describe the solution you'd like
A clear and concise description of what you want to happen.

增加调试功能, 为 任务增加 任务名,加入时间等信息, 然后 Pool 添加 Stats() []TaskInfo
为 Submit 添加一个些可选项,用户添加任务名,加入时间,
Submit(cb func(), opts ...TaskOption)

关于 <-p.freeSignal 的疑惑

Hi,
我阅读了源码,对 <-p.freeSignal 这句代码有疑惑。 这句代码出现在了多个地方,freeSignal 的作用英文注释我是理解的,并且知道在 putWorker 中才进行 p.freeSignal <- sig{}

对于下面的代码

func (p *Pool) getWorker() *Worker {
	var w *Worker
	waiting := false

	p.lock.Lock()
	idleWorkers := p.workers
	n := len(idleWorkers) - 1
	if n < 0 { // 说明 pool中没有worker了
		waiting = p.Running() >= p.Cap()
	} else { // 说明pool中有worker
		<-p.freeSignal      
		w = idleWorkers[n]  
		idleWorkers[n] = nil
		p.workers = idleWorkers[:n]
	}
	p.lock.Unlock()


func (p *Pool) Release() error {
	p.once.Do(func() { // 保证只释放一次
		p.release <- sig{}
		p.lock.Lock()
		idleWorkers := p.workers
		for i, w := range idleWorkers {
			<-p.freeSignal
			w.task <- nil
			idleWorkers[i] = nil
		}
		p.workers = nil
		p.lock.Unlock()
	})
	return nil
}

中的 <-p.freeSignal, 那不是要等putWorker触发了才会继续进行吗?如果 putWorker不触发,就一直阻塞在那了,即使 idleWorkers 中可能是有worker的

可否解释下这边的逻辑?谢谢

cap 和 running 比较的问题

这是我在 Playground 上面的代码 https://play.golang.org/p/D94YUU3FnX6
atomic 只能保证自增自减时的原子操作,在比较过程中,其他线程对变量进行了操作 比较过程并无感知,所以这个比较结果 不是完全正确的,想要实现 比较的数量完全正确,只能在修改和比较两个值的地方加锁
#26 说的是对的

带选项的初始化函数,我觉得用 functional options 更好一点

以下是示意代码
如果用 functional options,原来的写法是

ants.NewPool(10)

新的写法,如果不加 option,写法是不变的,因为 options 是作为可变参数传进去的。如果要加 option,只需要改成

ants.NewPool(10, ants.WithNonblocking(true))

这样。

现在是直接传一个 Option 结构体进去,所有的地方都要改,感觉很不优雅。
具体 functional options 的设计可以看 rob pike 的一篇博客 https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html

业务逻辑 panic 问题

`package main

import (
"fmt"
"net"
"sync"
"time"

"github.com/panjf2000/ants/v2"

)

func doPortScan(i interface{}) {

port := i.(int32)

_, err := net.DialTimeout("tcp", fmt.Sprintf("192.168.20.1:%d", port), time.Second*1)
if err != nil {
	return
}

fmt.Printf("Port  %d is open\n", port)

}

func main() {
defer ants.Release()

runTimes := 65535

// Use the common pool.
var wg sync.WaitGroup


// Use the pool with a method,
// set 10 to the capacity of goroutine pool and 1 second for expired duration.
p, _ := ants.NewPoolWithFunc(300, func(i interface{}) {
	doPortScan(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())

}
崩溃时的现象如下:
goroutine 543 [runnable]:
github.com/panjf2000/ants/v2.(*goWorkerWithFunc).run.func1(0xc000255e00)
/Users/mac/go/src/github.com/panjf2000/ants/worker_func.go:65 +0x85
created by github.com/panjf2000/ants/v2.(*goWorkerWithFunc).run
/Users/mac/go/src/github.com/panjf2000/ants/worker_func.go:49 +0x4c

goroutine 544 [runnable]:
syscall.syscall(0x108b820, 0x25, 0xc00048800c, 0x10, 0xffffffffffffffff, 0xffffffffffffffff, 0x24)
/usr/local/go/src/runtime/sys_darwin.go:63 +0x2e
syscall.connect(0x25, 0xc00048800c, 0x10, 0x0, 0x0)
/usr/local/go/src/syscall/zsyscall_darwin_amd64.go:91 +0x5c
syscall.Connect(0x25, 0x1158f40, 0xc000488000, 0x111ac80, 0x1)
/usr/local/go/src/syscall/syscall_unix.go:251 +0x62
net.(*netFD).connect(0xc0000e2180, 0x115a280, 0xc0003ff200, 0x0, 0x0, 0x1158f40, 0xc000488000, 0x0, 0x0, 0x0, ...)
/usr/local/go/src/net/fd_unix.go:70 +0x7b
net.(*netFD).dial(0xc0000e2180, 0x115a280, 0xc0003ff200, 0x115a7a0, 0x0, 0x115a7a0, 0xc000255e90, 0x0, 0x1, 0xc000061890)
/usr/local/go/src/net/sock_posix.go:149 +0xff
net.socket(0x115a280, 0xc0003ff200, 0x1133ff4, 0x3, 0x2, 0x1, 0x0, 0x0, 0x115a7a0, 0x0, ...)
/usr/local/go/src/net/sock_posix.go:70 +0x1c0
net.internetSocket(0x115a280, 0xc0003ff200, 0x1133ff4, 0x3, 0x115a7a0, 0x0, 0x115a7a0, 0xc000255e90, 0x1, 0x0, ...)
/usr/local/go/src/net/ipsock_posix.go:141 +0x141
net.(*sysDialer).doDialTCP(0xc0000e2100, 0x115a280, 0xc0003ff200, 0x0, 0xc000255e90, 0x110a680, 0x123ab20, 0x0)
/usr/local/go/src/net/tcpsock_posix.go:65 +0xc2
net.(*sysDialer).dialTCP(0xc0000e2100, 0x115a280, 0xc0003ff200, 0x0, 0xc000255e90, 0xc034fda0d3, 0x121ffc0, 0xc000061ad0)
/usr/local/go/src/net/tcpsock_posix.go:61 +0xd7
net.(*sysDialer).dialSingle(0xc0000e2100, 0x115a280, 0xc0003ff200, 0x11593c0, 0xc000255e90, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/dial.go:578 +0x36e
net.(*sysDialer).dialSerial(0xc0000e2100, 0x115a280, 0xc0003ff200, 0xc0000b38a0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/dial.go:546 +0x221
net.(*Dialer).DialContext(0xc000061e40, 0x115a240, 0xc0000ce008, 0x1133ff4, 0x3, 0xc0000ce6f0, 0x10, 0x0, 0x0, 0x0, ...)
/usr/local/go/src/net/dial.go:424 +0x666
net.(*Dialer).Dial(...)
/usr/local/go/src/net/dial.go:347
net.DialTimeout(0x1133ff4, 0x3, 0xc0000ce6f0, 0x10, 0x3b9aca00, 0xc0000ce6f0, 0x10, 0x0, 0x0)
/usr/local/go/src/net/dial.go:333 +0xb5
main.doPortScan(0x10fe540, 0xc0000ce6d4)
/Users/mac/go/src/github.com/panjf2000/ants/examples/main.go:42 +0xd8
main.main.func1(0x10fe540, 0xc0000ce6d4)
/Users/mac/go/src/github.com/panjf2000/ants/examples/main.go:90 +0x3e
github.com/panjf2000/ants/v2.(*goWorkerWithFunc).run.func1(0xc000255e30)
/Users/mac/go/src/github.com/panjf2000/ants/worker_func.go:69 +0xbd
created by github.com/panjf2000/ants/v2.(*goWorkerWithFunc).run
/Users/mac/go/src/github.com/panjf2000/ants/worker_func.go:49 +0x4c
exit status 2`

为什么我无法获取到 v2 版本

go get -u github.com/panjf2000/ants/v2

package github.com/panjf2000/ants/v2: cannot find package "github.com/panjf2000/ants/v2" in any of:
        /usr/local/go/src/github.com/panjf2000/ants/v2 (from $GOROOT)
        /Users/xxx/Desktop/go/gin/src/github.com/panjf2000/ants/v2 (from $GOPATH)

是否考虑 worker 中添加 PanicHandler ?

比方说在创建 Pool 的时候传入一个 PanicHandler,然后在每个 worker 创建的时候 recover 之后传给 PanicHandler 处理。否则池子里如果发生 panic 会直接挂掉整个进程。

为什么我无法获取到 v2 版本

go get -u github.com/panjf2000/ants/v2

package github.com/panjf2000/ants/v2: cannot find package "github.com/panjf2000/ants/v2" in any of:
        /usr/local/go/src/github.com/panjf2000/ants/v2 (from $GOROOT)
        /Users/xxx/Desktop/go/gin/src/github.com/panjf2000/ants/v2 (from $GOPATH)

worker 在 revertworker 返回 false 退出时没有 decRunning

Describe the bug
A clear and concise description of what the bug is.
retrieveWorker 中,有一个分支是判 p.Running() < p.Cap(),然后 spawnWorker;由于这个地方没锁,可能很多个 goroutine 都进入到了这个地方,超过了 Cap 的数量。

worker 完成工作之后,revertWorker,会发现 Running > Cap ,返回 false,worker 就会退出,退出前没有减 Running,导致 Running 始终大于 Cap,池子卡死。

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error
    生产环境高负载下压出来的。

Expected behavior
A clear and concise description of what you expected to happen.
导致池子卡住。

Error messages/Trace logs
If applicable, add some logs to help explain your problem.

System info (please complete the following information):

  • OS: [e.g. linux, macOS]
  • Go Version [e.g. 1.12]

Additional context
Add any other context about the problem here.

Checksum mismatch for go 1.13

Expect (go version go1.12.9 darwin/amd64):

→ go mod tidy -v
go: downloading github.com/panjf2000/ants v1.2.0
go: extracting github.com/panjf2000/ants v1.2.0

Actual (go version go1.13 darwin/amd64)

→ go mod tidy -v
verifying github.com/panjf2000/[email protected]: checksum mismatch
        downloaded: h1:Ufw4aDz9RqH1RVblx2W9L9Uv5vSX5apbX5+peR7LQ5k=
        sum.golang.org: h1:pMQ1/XpSgnWx3ro4y1xr/uA3jXUsTuAaU3Dm0JjwggE=

SECURITY ERROR
This download does NOT match the one reported by the checksum server.
The bits may have been replaced on the origin server, or an attacker may
have intercepted the download attempt.

For more information, see 'go help module-auth'.

UPD: mb this issue will be useful - golang/go#33665


UPD: how resolve issue step by step (macOS):

  • sudo go clean -modcache
  • git checkout go.sum
  • go mod tidy -v

UPD for Linux:

  • cd /another/path
  • go clean -modcache
  • cd /project/path
  • go mod tidy

Benchmark 下直接使用 Semaphore 似乎更快呢?

简单跑了一下 benchmark,Semaphore 更快且很简单

$ go test -bench .
goos: darwin
goarch: amd64
pkg: github.com/panjf2000/ants
BenchmarkGoroutineWithFunc-4   	       1	3445631705 ns/op
BenchmarkSemaphoreWithFunc-4   	       1	1037219073 ns/op
BenchmarkAntsPoolWithFunc-4    	       1	1138053222 ns/op
BenchmarkGoroutine-4           	       2	 731850771 ns/op
BenchmarkSemaphore-4           	       2	 914855967 ns/op
BenchmarkAntsPool-4            	       1	1094379445 ns/op
PASS
ok  	github.com/panjf2000/ants	33.173s

那 Ants 在什么情况下有优势呢?

go协程的理解

你好楼主,向您请教一个协程和线程的问题,协程基于go进程调度,线程基于系统内核调度,调度协程的过程是先调度线程后获得资源再去调度协程。"官方解释: GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously。限制cpu数,本质上是什么,限制并行数?,并行数即同时执行数量?,执行单元即线程?,即限制最大并行线程数量?"

workerCache 没有初始化

Describe the bug
A clear and concise description of what the bug is.
没有设置 New 函数,这个是忘了还是有什么玄机呢
To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Error messages/Trace logs
If applicable, add some logs to help explain your problem.

System info (please complete the following information):

  • OS: [e.g. linux, macOS]
  • Go Version [e.g. 1.12]

Additional context
Add any other context about the problem here.

retrieveWorker与revertWorker之间会导致死锁

func (p *Pool) retrieveWorker() *Worker {
var w *Worker

**p.lock.Lock()**
idleWorkers := p.workers
n := len(idleWorkers) - 1
if n >= 0 {
	w = idleWorkers[n]
	idleWorkers[n] = nil
	p.workers = idleWorkers[:n]
	p.lock.Unlock()
} else if p.Running() < p.Cap() {
	p.lock.Unlock()
	if cacheWorker := p.workerCache.Get(); cacheWorker != nil {
		w = cacheWorker.(*Worker)
	} else {
		w = &Worker{
			pool: p,
			task: make(chan func(), workerChanCap),
		}
	}
	w.run()
} else {
	for {
		**p.cond.Wait()** 
		l := len(p.workers) - 1
		if l < 0 {
			continue
		}
		w = p.workers[l]
		p.workers[l] = nil
		p.workers = p.workers[:l]
		break
	}
	**p.lock.Unlock()**
}
return w

}

// revertWorker puts a worker back into free pool, recycling the goroutines.
func (p *Pool) revertWorker(worker *Worker) bool {
if CLOSED == atomic.LoadInt32(&p.release) {
return false
}
worker.recycleTime = time.Now()
p.lock.Lock() // 协程池满了之后获取不到锁
p.workers = append(p.workers, worker)
// Notify the invoker stuck in 'retrieveWorker()' of there is an available worker in the worker queue.
p.cond.Signal()
p.lock.Unlock()
return true
}

优先级队列支持

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
优先级调度。比如除了 Submit 之外,提供 SubmitUrge 接口之类的,提供多优先级调度功能

Describe the solution you'd like
A clear and concise description of what you want to happen.
最简单的办法,可以做三个队列,最高的是 urgent,最低的是 delayed,中间的就是现在的队列。调度策略可以开成 interface 方便定制,简单的策略可以类似于内核 io 调度的 deadline 调度器。

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
只能做多个 pool,但是也不好实现多个 pool 之间的优先级调度。

Additional context
Add any other context or screenshots about the feature request here.
确实有高优先级调度的需求

请不要再随意变更版本号了。。。

之前用的是 3.9.9,结果今天构建出了问题,一看发现这个版本没了,变成 1.0.0。这种变更完全不考虑现有用户的情况。希望以后不要随意变更了

goroutine 不是协程,项目描述不准确。

Describe the bug
A clear and concise description of what the bug is.

目前的项目描述里提到,“ ants 是一个高性能且低损耗的 goroutine 协程池。”,这个说法是不正确的,goroutine 不是协程。

首先,goroutine 不是我们通常说的协作式调度,绝大部分的 go 程序都是没有 runtime.Gosched 的。如果认为 go scheduler 内部的抢占调度目前不完善,那 linux 内核在 2.几 某个版本之前也没有完善的抢占调度,难道 linux 线程也是协程吗。

另外,预期 Go 1.14 就有完全的抢占调度了,更跟协程不搭边了。

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Error messages/Trace logs
If applicable, add some logs to help explain your problem.

System info (please complete the following information):

  • OS: [e.g. linux, macOS]
  • Go Version: [e.g. 1.12]
  • ants version: [e.g. v2.2.2]

Additional context
Add any other context about the problem here.

Hi, boys

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

running可能大于cap的问题

running与cap的比较判断与incRuning分开执行的, 可能会出现running大于cap的问题?
`func (p *Pool) retrieveWorker() *Worker {
var w *Worker

p.lock.Lock()
idleWorkers := p.workers
n := len(idleWorkers) - 1
if n >= 0 {
	w = idleWorkers[n]
	idleWorkers[n] = nil
	p.workers = idleWorkers[:n]
	p.lock.Unlock()
} else if p.Running() < p.Cap() {
	p.lock.Unlock()
	if cacheWorker := p.workerCache.Get(); cacheWorker != nil {
		w = cacheWorker.(*Worker)
	} else {
		w = &Worker{
			pool: p,
			task: make(chan func(), workerChanCap),
		}
	}
	w.run()`

go1.8无法运行benchmark测试

你好,我的本地环境和生产环境都是go1.8,目前通过go get会报cannot find package "github.com/panjf2000/ants/v2/internal”错误,而go1.8还不支持go modules。
想问一下这个代码需要做哪些变动才可以运行在go1.8上呢?你们可以提供支持么?
谢谢~ #62

p.Tune is only for cutting down pool size, but not support enlarge.

In the Tune Method, the scale up the pool size should be supported also.
So, before do the pool size change, check which one is bigger for the p.Running() and size, the using the bigger one to minus the small one, then assign the result to diff.
What do you think?

func (p *Pool) Tune(size uint)
...
### diff := p.Running() - int(size)
for i := 0; i < diff; i++ {
p.retrieveWorker().task <- nil
}

workers 使用slice 还是list问题

看了下代码, Pool是用slice来装workers, 但Pool的操作中,除了purge和release中需要遍历workers, getWorker和putWorker 都是对队尾出队入队的操作, 是否可以考虑用 container/list ? (假设,还没验证)。

另外还有个问题, 在putWokers时有个append操作, 这里是不是可以在NewPool时, 给workers slice 预分配一些空间呢?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.