如何管理|如何管理 Goroutine

为什么需要管理Goroutines 有效利用资源
虽然在Golang程序中,使用go func的方式开启一个goroutine协程是非常轻量级的操作。但是,完全不管理的任意创建,会造成很多资源的浪费。虽然golang本身提供了GC功能,但是GC释放是需要时机的。通过更加合理的创建goroutine对象可以更加有效的利用系统资源。
贴一个常见的资源问题:

for { go func(){ fmt.Println("xxx") }() }

这段代码可能造成两类对象资源的浪费:
  • 函数对象资源的浪费
  • goroutine资源的浪费
以上代码,读者可以长时间运行看看程序对于系统资源的占用情况。
上下文控制
随着程序复杂度的上升,goroutine通常也会随之增长。如何控制这些新创建的goroutine呢。这就需要通过context.Context上下文对象,进行父子级传递,完成父子goroutine的控制。
如何实现Goroutine的管理 除了以上两点原因之外,针对goroutine的管理,还可以提供以下功能的扩展:
  • goroutine pool协程池管理
  • go crontab job定时任务管理
具体的实现已经初步实现在该项目 github.com/x-mod/routine 中。
github.com/x-mod/routine dedicated goroutine managment for go main, go func, go routine pool, go crontab jobs.
  • go main
  • go func
  • go routine pool
  • go crontab jobs
Quick Start In routine package, it use the Executor interface or ExecutorFunc instance for your implemention.
type Executor interface{ Execute(context.Context, ...interface{}) }type ExecutorFunc func(context.Context, ...interface{})

Go Main
routine.Main is the basic function, when use the routine package. The routine.Main does the following things for you:
  • arguments from context
  • support signal interupts
  • support context wait & cancel
import "github.com/x-mod/routine"func main(){ routine.Main(routine.WithArguments(context.TODO(), "first arg", "second", false), ExecutorFunc(func(ctx context.Context, args ...interface{}){ //out put args log.Println(args...)}), routine.DefaultCancelInterruptors...) }# output # first arg second false

define your own signal interruptor
// InterruptHandler definition type InterruptHandler func(ctx context.Context, cancel context.CancelFunc) (exit bool)// Interruptor definition type Interruptor interface { Signal() os.Signal Interrupt() InterruptHandler }

Go Func
routine.Go is the wrapper for the system keyword go, this function should used in the routine.Main scope. It does the following this:
  • sync.wait Add & Done
  • context.Context Done check for executor go routine
import "github.com/x-mod/routine"func main(){ routine.Main(context.TODO(), ExecutorFunc(func(ctx context.Context, args ...interface{}){routine.Go(routine.WithArguments(ctx, args1...), Executor1) routine.Go(routine.WithArguments(ctx, args2...), Executor2)}), routine.DefaultCancelInterruptors...) }

Go routine pool
routine.Pool is the go routine pool manager. you should use it in routine.Main scope either, for the routine.Main controls the routines exiting events. And the routine.Pool does the following things for you:
  • go routines management, like auto create new routine & release idle routine
  • support fixed Executor & dynamic Executor
  • async invoke functions
dynamic executor example:
import "github.com/x-mod/routine"func main(){routine.Main(context.Backgroud(), ExecutorFunc(func(ctx context.Context, args ...interface{}){ //dynamic executors pool pool := routine.NewPool(routine.RunningSize(4), routine.WatingSize(8))//open if err := pool.Open(ctx); err != nil { //TODO return } //close defer pool.Close()//async invoke multiple dynamic executors pool.Go(routine.WithArguments(ctx, args1...), executor1) pool.Go(routine.WithArguments(ctx, args2...), executor2)}), routine.DefaultCancelInterruptors...) }

fixed executor example:
import "github.com/x-mod/routine"func main(){routine.Main(context.Backgroud(), ExecutorFunc(func(ctx context.Context, args ...interface{}){//fixed executor pool fixedPool := routine.NewPool(routine.RunningSize(4), routine.WatingSize(8), routine.FixedExecutor(executor3))//open if err := fixedPool.Open(ctx); err != nil { //TODO return } //close defer fixedPool.Close()//async invoke fixed executor fixedPool.Execute(ctx, args1...) fixedPool.Execute(ctx, args2...)}), routine.DefaultCancelInterruptors...) }

Go crontab jobs
【如何管理|如何管理 Goroutine】routine.Crontab is similar interface like linux system's crontab jobs. You can
import "github.com/x-mod/routine"func main(){ crontab := routine.NewCrontab(routine.RunningSize(4)) defer crontab.Close()routine.Main(context.Backgroud(), ExecutorFunc(func(ctx context.Context, args ...interface{}){//open crontab if err := crontab.Open(ctx); err != nil { //TODO return }// crontab format schedule crontab.JOB("* * * * *", executor1).Go(ctx, args1...) crontab.JOB("* * * * *", executor2).Go(ctx, args2...)// every interval crontab.EVERY(time.Second, executor3).Go(ctx, args3 ...) crontab.EVERY(time.Minute, executor4).Go(ctx, args4 ...)// now, run executor at once crontab.NOW(executor5).Go(ctx, args5...)}), routine.DefaultCancelInterruptors...) }

    推荐阅读