├── .gitignore ├── .travis.yml ├── grmanager_test.go ├── LICENSE ├── grchannel.go ├── grmanager.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .swp 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | 4 | go: 5 | - 1.3 6 | - 1.4 7 | - 1.5 8 | - tip 9 | -------------------------------------------------------------------------------- /grmanager_test.go: -------------------------------------------------------------------------------- 1 | package grtm 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func HelloWorld() { 10 | fmt.Println("Hello world!") 11 | } 12 | 13 | func Test_StopLoopGoroutine(t *testing.T) { 14 | gm := NewGrManager() 15 | // start a loop goroutine named 'test' 16 | gm.NewLoopGoroutine("test", func(args ...interface{}) { 17 | c := args[0].([]interface{})[0].(int) + args[0].([]interface{})[1].(int) 18 | fmt.Println(c) 19 | }, 1, 2) 20 | // start a loop goroutine named 'hello' 21 | gm.NewLoopGoroutine("hello", HelloWorld) 22 | time.Sleep(time.Duration(2) * time.Second) 23 | // stop a loop goroutine named 'test' 24 | err := gm.StopLoopGoroutine("test") 25 | if err != nil { 26 | t.Error(err) 27 | } 28 | time.Sleep(time.Duration(5) * time.Second) 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2014 sk,http://cocosk.com/ ,skkmvp@hotmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /grchannel.go: -------------------------------------------------------------------------------- 1 | package grtm 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sync" 7 | ) 8 | 9 | const ( 10 | STOP = "__P:" 11 | ) 12 | 13 | type GoroutineChannel struct { 14 | gid uint64 15 | name string 16 | msg chan string 17 | } 18 | 19 | type GoroutineChannelMap struct { 20 | mutex sync.Mutex 21 | grchannels map[string]*GoroutineChannel 22 | } 23 | 24 | func (m *GoroutineChannelMap) unregister(name string) error { 25 | m.mutex.Lock() 26 | defer m.mutex.Unlock() 27 | if _, ok := m.grchannels[name]; !ok { 28 | return fmt.Errorf("goroutine channel not find: %q", name) 29 | } 30 | delete(m.grchannels, name) 31 | return nil 32 | } 33 | 34 | func (m *GoroutineChannelMap) register(name string) error { 35 | gchannel := &GoroutineChannel{ 36 | gid: uint64(rand.Int63()), 37 | name: name, 38 | } 39 | gchannel.msg = make(chan string) 40 | m.mutex.Lock() 41 | defer m.mutex.Unlock() 42 | if m.grchannels == nil { 43 | m.grchannels = make(map[string]*GoroutineChannel) 44 | } else if _, ok := m.grchannels[gchannel.name]; ok { 45 | return fmt.Errorf("goroutine channel already defined: %q", gchannel.name) 46 | } 47 | m.grchannels[gchannel.name] = gchannel 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /grmanager.go: -------------------------------------------------------------------------------- 1 | package grtm 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | type GrManager struct { 10 | grchannelMap *GoroutineChannelMap 11 | } 12 | 13 | func NewGrManager() *GrManager { 14 | gm := &GoroutineChannelMap{} 15 | return &GrManager{grchannelMap: gm} 16 | } 17 | 18 | func (gm *GrManager) StopLoopGoroutine(name string) error { 19 | stopChannel, ok := gm.grchannelMap.grchannels[name] 20 | if !ok { 21 | return fmt.Errorf("not found goroutine name :" + name) 22 | } 23 | gm.grchannelMap.grchannels[name].msg <- STOP + strconv.Itoa(int(stopChannel.gid)) 24 | return nil 25 | } 26 | 27 | func (gm *GrManager) NewLoopGoroutine(name string, fc interface{}, args ...interface{}) { 28 | go func(this *GrManager, n string, fc interface{}, args ...interface{}) { 29 | //register channel 30 | err := this.grchannelMap.register(n) 31 | if err != nil { 32 | return 33 | } 34 | for { 35 | select { 36 | case info := <-this.grchannelMap.grchannels[name].msg: 37 | taskInfo := strings.Split(info, ":") 38 | signal, gid := taskInfo[0], taskInfo[1] 39 | if gid == strconv.Itoa(int(this.grchannelMap.grchannels[name].gid)) { 40 | if signal == "__P" { 41 | fmt.Println("gid[" + gid + "] quit") 42 | this.grchannelMap.unregister(name) 43 | return 44 | } else { 45 | fmt.Println("unknown signal") 46 | } 47 | } 48 | default: 49 | fmt.Println("no signal") 50 | } 51 | 52 | if len(args) > 1 { 53 | fc.(func(...interface{}))(args) 54 | } else if len(args) == 1 { 55 | fc.(func(interface{}))(args[0]) 56 | } else { 57 | fc.(func())() 58 | } 59 | } 60 | }(gm, name, fc, args...) 61 | } 62 | 63 | func (gm *GrManager) NewGoroutine(name string, fc interface{}, args ...interface{}) { 64 | go func(n string, fc interface{}, args ...interface{}) { 65 | //register channel 66 | err := gm.grchannelMap.register(n) 67 | if err != nil { 68 | return 69 | } 70 | if len(args) > 1 { 71 | fc.(func(...interface{}))(args) 72 | } else if len(args) == 1 { 73 | fc.(func(interface{}))(args[0]) 74 | } else { 75 | fc.(func())() 76 | } 77 | gm.grchannelMap.unregister(name) 78 | }(name, fc, args...) 79 | 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # about grtm 2 | [![Build Status](https://travis-ci.org/scottkiss/grtm.svg?branch=master)](https://travis-ci.org/scottkiss/grtm) 3 | 4 | grtm is a tool to manage golang goroutines.use this can start or stop a long loop goroutine. 5 | 6 | ## Getting started 7 | ```bash 8 | go get github.com/scottkiss/grtm 9 | ``` 10 | 11 | ## Create normal goroutine 12 | 13 | ```golang 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "github.com/scottkiss/grtm" 19 | "time" 20 | ) 21 | 22 | func normal() { 23 | fmt.Println("i am normal goroutine") 24 | } 25 | 26 | func main() { 27 | gm := grtm.NewGrManager() 28 | gm.NewGoroutine("normal", normal) 29 | fmt.Println("main function") 30 | time.Sleep(time.Second * time.Duration(5)) 31 | } 32 | ~ 33 | ``` 34 | 35 | ## Create normal goroutine function with params 36 | 37 | ```golang 38 | package main 39 | 40 | import ( 41 | "fmt" 42 | "github.com/scottkiss/grtm" 43 | "time" 44 | ) 45 | 46 | func normal() { 47 | fmt.Println("i am normal goroutine") 48 | } 49 | 50 | func funcWithParams(args ...interface{}) { 51 | fmt.Println(args[0].([]interface{})[0].(string)) 52 | fmt.Println(args[0].([]interface{})[1].(string)) 53 | } 54 | 55 | func main() { 56 | gm := grtm.NewGrManager() 57 | gm.NewGoroutine("normal", normal) 58 | fmt.Println("main function") 59 | gm.NewGoroutine("funcWithParams", funcWithParams, "hello", "world") 60 | time.Sleep(time.Second * time.Duration(5)) 61 | } 62 | ``` 63 | 64 | ## Create long loop goroutine then stop it 65 | 66 | ```golang 67 | package main 68 | 69 | import ( 70 | "fmt" 71 | "github.com/scottkiss/grtm" 72 | "time" 73 | ) 74 | 75 | func myfunc() { 76 | fmt.Println("do something repeat by interval 4 seconds") 77 | time.Sleep(time.Second * time.Duration(4)) 78 | } 79 | 80 | func main() { 81 | gm := grtm.NewGrManager() 82 | gm.NewLoopGoroutine("myfunc", myfunc) 83 | fmt.Println("main function") 84 | time.Sleep(time.Second * time.Duration(40)) 85 | fmt.Println("stop myfunc goroutine") 86 | gm.StopLoopGoroutine("myfunc") 87 | time.Sleep(time.Second * time.Duration(80)) 88 | } 89 | ``` 90 | 91 | output 92 | 93 | ```bash 94 | main function 95 | no signal 96 | do something repeat by interval 4 seconds 97 | no signal 98 | do something repeat by interval 4 seconds 99 | no signal 100 | do something repeat by interval 4 seconds 101 | no signal 102 | do something repeat by interval 4 seconds 103 | no signal 104 | do something repeat by interval 4 seconds 105 | no signal 106 | do something repeat by interval 4 seconds 107 | no signal 108 | do something repeat by interval 4 seconds 109 | no signal 110 | do something repeat by interval 4 seconds 111 | no signal 112 | do something repeat by interval 4 seconds 113 | no signal 114 | do something repeat by interval 4 seconds 115 | stop myfunc goroutine 116 | gid[5577006791947779410] quit 117 | 118 | ``` 119 | 120 | 121 | --------------------------------------------------------------------------------