Go 学习笔记(二十六)指定 goroutine 的执行顺序
本文原创地址:博客园骏马金龙Go 基础系列:指定 goroutine 的执行顺序
当关闭一个 channel 时,会使得这个 channel 变得可读。通过这个特性,可以实现一个 goroutine 执行顺序的技巧。
如果一个 goroutine A 依赖于另一个 goroutine B,在 goroutine A 中首先通过读 goroutine B 来阻塞自己,直到 goroutine B 关闭自身之后,goroutine A 才会继续运行。这样,goroutine B 就先于 goroutine A 运行。
下面是一个指定 goroutine 执行顺序的示例,它保证的顺序是A()-->B()-->C()
。
package main
import (
"fmt"
"time"
)
// A首先被a阻塞,A()结束后关闭b,使b可读
func A(a, b chan struct{}) {
<-a
fmt.Println("A()!")
time.Sleep(time.Second)
close(b)
}
// B首先被a阻塞,B()结束后关闭b,使b可读
func B(a, b chan struct{}) {
<-a
fmt.Println("B()!")
close(b)
}
// C首先被a阻塞
func C(a chan struct{}) {
<-a
fmt.Println("C()!")
}
func main() {
x := make(chan struct{})
y := make(chan struct{})
z := make(chan struct{})
go C(z)
go A(x, y)
go C(z)
go B(y, z)
go C(z)
// 关闭x,让x可读
close(x)
time.Sleep(3 * time.Second)
}
上面的示例中:A goroutine 被 x 阻塞,B goroutine 被 y 阻塞,C goroutine 被 z 阻塞。C 依赖的 z 由 B 关闭,B 依赖的 y 由 A 关闭。
如此一来,当 main goroutine 中的 x 被关闭后,A()从阻塞中释放,继续执行,关闭 y,然后 B 从阻塞中释放,继续执行,关闭 z,C 得以释放。由于 z 被关闭后,z 仍然可读,所以多次执行 C(z) 不会出问题。
A()和 B() 不能多次执行,因为 close() 不能操作已被关闭的 channel。
注意,上面的 channel 都是struct{}
类型的,整个过程中,x、y、z 这 3 个通道都没有传递数据,而是直接关闭来释放通道,让某些阻塞的 goroutine 继续执行下去。显然,这里的 x、y、z 的作用都是 "信号通道",用来传递消息。
上一篇 Go 学习笔记(二十五)双层 channel 用法示例
Go 学习笔记(目录)
下一篇 Go 学习笔记(二十七)互斥锁 Mutex 和读写锁 RWMutex 用法详述