如何管理 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 forgo main
,go func
,go routine pool
,go crontab jobs
.
- go main
- go func
- go routine pool
- go crontab jobs
Quick Start
Inroutine
package, it use theExecutor
interface orExecutorFunc
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 theroutine
package. Theroutine.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 keywordgo
, this function should used in theroutine.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 inroutine.Main
scope either, for theroutine.Main
controls the routines exiting events. And theroutine.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
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...) }