Go语言Goroutine特性及使用…
Goroutine 之间常用的通信方式有:
sync.WaitGroup
如果只是单纯的等待所有任务完成,可以使用 sync.WaitGroup
:
1 2 3 4 5 6 7 8 9 10 11 12 13
| func main() { var wg sync.WaitGroup for i := 0; i < 3; i++ { wg.Add(1) go func() { fmt.Println("func run") time.Sleep(time.Second) wg.Done() }() } wg.Wait() fmt.Println("main done") }
|
全局变量
简单,但是传递的数据只能一写多读。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var stop bool
func main() { go f() time.Sleep(2 * time.Second) stop = false time.Sleep(2 * time.Second) fmt.Println("main done") } func f() { for stop { fmt.Println("still run") time.Sleep(time.Second) } }
|
channel
CSP 并发编程模型(Communicating Sequential Process)。channel 在 Golang 中是核心类型。
Golang 的 select 机制在语言层面实现了类似 Linux 的 select 功能,可以监听多个文件描述符的读写事件,能够在事件发生时主动通知应用程序处理。
Golang 的 select 还可以设置 default,在监听的事件全部阻塞时执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| func main() { stop := make(chan bool) go f(stop) time.Sleep(2 * time.Second) stop<-true time.Sleep(2 * time.Second) fmt.Println("main done") }
func f(stop chan bool) { for { select { case <-stop: fmt.Println("done") return default: fmt.Println("still run") time.Sleep(time.Second) } } }
|
context 上下文
Golang 的上下文是树状结构,通过 context.Background() 方法可以拿到上下文的根节点。常用方法有:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
WithCancel
子上下文可以调用 Done 方法(返回 channel,可以通过 select 读取)检测是否有父节点调用 cancel。上层节点的 cancel
调用会沿着上下文树的边向下通知到每一个子节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| func main() { ctx, myCancel := context.WithCancel(context.Background()) go func() { for { select { case <-ctx.Done(): fmt.Println("ctx Done") return default: fmt.Println("goroutine continue") time.Sleep(time.Second) } } }() time.Sleep(time.Second * 2) myCancel() time.Sleep(time.Second) fmt.Println("main done") }
|
WithValue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| type favContextKey string
func main() { ctx := context.WithValue(context.Background(), favContextKey("hello"), "Go") f := func(ctx context.Context, k favContextKey) { if v := ctx.Value(k); v != nil { fmt.Println("found value:", v) return } fmt.Println("value not found:", k) } f(ctx, favContextKey("hello")) f(ctx, favContextKey("color")) }
|