# goroutine **Repository Path**: fwhezfwhez/goroutine ## Basic Information - **Project Name**: goroutine - **Description**: https://github.com/fwhezfwhez/goroutine.git 的镜像。 - **Primary Language**: Go - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-03-05 - **Last Updated**: 2021-03-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## goroutine [goroutine] is a pkg which provides safe usage of using golang goroutine. To get well divided, `goroutine` is described as golang official object, and `[goroutine]` is described for this repo. ## Declaration [goroutine] is not redesigning another goroutine. It's just a wrap to make goroutine perform better in group team. ## Why do I design goroutine, rather than using `go func(){}()`? Golang basically supports goroutine and it's easy to use , like `go handler()`. It's just easy and convenient, however! Most of you should have been faced with these kind of questions: - A goroutine function panics and trigger your application node hung up or restart. [This is extremely fatal!!] - A goroutine once started, it's hardly being monitored. [There're too many goroutines in pprof/goroutine, hardly locate what you want!] - Most memory leak (by goroutine bursting) is caused by mis-understanding lifetime of a goroutine, this package force user to estimate how long your goroutine should have. Err will be reported if unexpected alive goroutine occurs. And thus, using [goroutine] will improve all advantages below: - Auto recovers if goroutine meets an inner panic.Besides, how to handle a panic can be set by `goroutine.HandlePanic = func(e interface{}) {}`. - Monitor zombie goroutines. - Alert and report those zombie goroutines. Know that using [goroutine] will have some extra cost for monitoring a goroutine, they're: - An extra goroutine to wait core goroutine to finish or timeout warning. - Each goroutine will be managed through a gss center, it's a concurrent map (It means two irrelevant goroutines are put into a race container, there should be lock cost too). But compare with your service logic, these cost is few. In which case you should use [goroutine]: - Most of your teammates are new. They're ones easier to produce panic. - Some of your jobs are important and just put into product use (it might cause unexpected leak or panic and thus should be monitored for some time). - Most of your service project creating goroutine. In which case you should use official goroutine: - You're designing a framework which has nothing to do with business. - You're excellent with goroutine and hardly produce unexpected zombie goroutines. - You've owned well-performed toolkit to detect goroutine leak and panic. - You just want to use goroutine as fast,clean as it can. To well divide which case to use and which not, here is some list: ✔ means should use [goroutine] ✖ means should use golang official goroutine | scene | should use | reason | |---|---|----| | start a cron job | ✔ | each job should have expected deadline, if hard to decide, set it bigger | | write a log asynchronously | ✔ | the same reason ↑ | | heartbeat routine on user connects | ✖ | this should well handled in framework, normally untouchable by teammate | | jobs with `sync.waitGroup` | ✔✖ | If job not done or expire, waitGroup will block which break your request, this is easy detect thus use [goroutine] or not both ok | | present extra props in shop exchange | ✔ | goroutine for service logic should always be well protected. These codes are often touched by teammates | ## Start `go get github.com/fwhezfwhez/goroutine` ## Usage ```go package main import ( "fmt" "goroutine" "math/rand" "runtime/debug" "time" ) func init() { // config zombie storage time goroutine.ZombieStorageSeconds = 3 * 24 * 60 * 60 // specific method to handle panic in goroutine goroutine.HandlePanic = func(e interface{}) { fmt.Printf("recv a panic from protected-go: %s \n %s \n", fmt.Sprintf("%v", e), debug.Stack()) } // specific method to alert a bad goroutine. goroutine.HandleBadGs = func(gs *goroutine.Gs) { fmt.Printf("recv a bad goroutine: %s\n", gs.Info()) } // Each 5 seconds spying on zombie goroutines go func() { for { info := goroutine.GlobalGss().Monitoring(10) fmt.Println(info) time.Sleep(5 * time.Second) } }() } func main() { // normal goroutines with short deadline for i := 0; i < 10000; i ++ { goroutine.ProtectedGo(func() { fmt.Println("normal goroutine") }, goroutine.GoParam{ UnqKey: fmt.Sprintf("test_protected_go_normal_goroutine_%d", i), ExpectedExpireSecond: 1, ShouldProtected: true, }) } // An eternal goroutine without deadline goroutine.ProtectedGo(func() { fmt.Println("an eternal goroutine") }, goroutine.GoParam{ UnqKey: "test_protected_go_eternal_goroutine", ExpectedExpireSecond: -1, ShouldProtected: true, }) // zombie goroutines. It expects 3s to run however lasting for 5 seconds for i := 0; i < 1000; i ++ { go func(i int) { time.Sleep(time.Duration(rand.Intn(10)%15) * time.Second) goroutine.ProtectedGo(func() { fmt.Println("a being zombie goroutine") time.Sleep(5 * time.Second) }, goroutine.GoParam{ UnqKey: fmt.Sprintf("test_protected_go_zombie_goroutine_%d", i), ExpectedExpireSecond: 3, ShouldProtected: true, }) }(i) } select {} } ```