线程等待与退出
N 线程同步等待
我们无法确定两个原子操作之间的顺序。解决问题的办法就是通过同步原语来给两个事件明确排序:
func main() {
done := make(chan int)
go func(){
println("你好, 世界")
done <- 1
}()
<-done
}
当 <-done
执行时,必然要求 done <- 1
也已经执行。根据同一个done <- 1
执行时,println("你好, 世界")
语句必然已经执行完成了。因此,现在的程序确保可以正常打印结果。当然,通过 sync.Mutex
互斥量也是可以实现同步的:
func main() {
var mu sync.Mutex
mu.Lock()
go func(){
println("你好, 世界")
mu.Unlock()
}()
mu.Lock()
}
可以确定后台线程的 mu.Unlock()
必然在 println("你好, 世界")
完成后发生(同一个线程满足顺序一致性main
函数的第二个 mu.Lock()
必然在后台线程的 mu.Unlock()
之后发生(sync.Mutex
保证
基于带缓存的管道,我们可以很容易将打印线程扩展到
func main() {
done := make(chan int, 10) // 带 10 个缓存
// 开N个后台打印线程
for i := 0; i < cap(done); i++ {
go func(){
fmt.Println("你好, 世界")
done <- 1
}()
}
// 等待N个后台线程完成
for i := 0; i < cap(done); i++ {
<-done
}
}
sync.WaitGroup
对于这种要等待
func main() {
var wg sync.WaitGroup
// 开N个后台打印线程
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
fmt.Println("你好, 世界")
wg.Done()
}()
}
// 等待N个后台线程完成
wg.Wait()
}
其中 wg.Add(1)
用于增加等待事件的个数,必须确保在后台线程启动之前执行(如果放到后台线程之中执行则不能保证被正常执行到wg.Done()
表示完成一个事件。main
函数的 wg.Wait()
是等待全部的事件完成。
并发的退出机制
有时候我们需要通知
基于
select {
case v := <-in:
fmt.Println(v)
case <-time.After(time.Second):
return // 超时
}
通过
select {
case v := <-in:
fmt.Println(v)
default:
// 没有数据
}
通过
func main() {
// do some thins
select{}
}
当有多个管道均可操作时,
func main() {
ch := make(chan int)
go func() {
for {
select {
case ch <- 0:
case ch <- 1:
}
}
}()
for v := range ch {
fmt.Println(v)
}
}
我们通过
func worker(cannel chan bool) {
for {
select {
default:
fmt.Println("hello")
// 正常工作
case <-cannel:
// 退出
}
}
}
func main() {
cannel := make(chan bool)
go worker(cannel)
time.Sleep(time.Second)
cannel <- true
}
但是管道的发送操作和接收操作是一一对应的,如果要停止多个
func worker(cannel chan bool) {
for {
select {
default:
fmt.Println("hello")
// 正常工作
case <-cannel:
// 退出
}
}
}
func main() {
cancel := make(chan bool)
for i := 0; i < 10; i++ {
go worker(cancel)
}
time.Sleep(time.Second)
close(cancel)
}
我们通过
func worker(wg *sync.WaitGroup, cannel chan bool) {
defer wg.Done()
for {
select {
default:
fmt.Println("hello")
case <-cannel:
return
}
}
}
func main() {
cancel := make(chan bool)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go worker(&wg, cancel)
}
time.Sleep(time.Second)
close(cancel)
wg.Wait()
}
现在每个工作者并发体的创建、运行、暂停和退出都是在