书接上回,在golang中使用go关键字即可创建协程。实际上,一个golang脚本运行起来后,应用主协程外,还有协程调度器, gc等多个“系统”级的协程存在,不过我们一般不用太过度关注它们。
我们使用go关键字创建的协程,与我们的应用主协程之间,是会被并行调度的,因此执行的顺序是不确定的。它们之间需要必定的同步机制。
package main
import "time"
func main() {
go func() {
println("这是子协程")
}()
time.Sleep(2 * time.Second)
println("这是主协程")
println("done.")
}
运行:
> go run main.go
这是子协程
这是主协程
done.
我们看到了主协程使用了time.Sleep等待子协程的执行结束。这是一种最简单的方式,只适合用在有限的场景。
golang中提供了sync.WaitGroup用于协程的同步:
package main
import (
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
println("这是子协程:", idx)
}(i)
}
wg.Wait()
println("这是主协程")
println("done.")
}
运行:
> go run main.go
这是子协程: 0
这是子协程: 4
这是子协程: 1
这是子协程: 2
这是子协程: 3
这是主协程
done.
我们看到了通过使用sync.WaitGroup,保证了所有相关协程在某个点上的同步结束。注意Add/Done/Wait等成员函数被调用的位置。
channel类型一般用于协程间的,包括主协程与子协程间数据的通信。同时通过channel的关闭也可以通知子协程结束:
package main
import (
"sync"
)
func main() {
ch := make(chan bool, 10)
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(idx int, _ch chan bool) {
defer wg.Done()
for {
select {
case _, ok := <-_ch:
if !ok { // channel is closed
println("子协程关闭:", idx)
return
}
}
}
}(i, ch)
}
close(ch)
wg.Wait()
println("这是主协程")
println("done.")
}
运行:
> go run main.go
子协程关闭: 0
子协程关闭: 1
子协程关闭: 3
子协程关闭: 4
子协程关闭: 2
这是主协程
done.
当然,也可以使用context(上下文)通知子协程结束:
package main
import (
"context"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(idx int, _ctx context.Context) {
defer wg.Done()
for {
select {
case <-ctx.Done():
println("子协程关闭:", idx)
return
default:
// 子协程处理逻辑
time.Sleep(1 * time.Second)
}
}
}(i, ctx)
}
cancel()
wg.Wait()
println("这是主协程")
println("done.")
}
运行:
> go run main.go
子协程关闭: 4
子协程关闭: 3
子协程关闭: 0
子协程关闭: 2
子协程关闭: 1
这是主协程
done.
最后,sync.Mutex(锁)和sync.RWMutex(读写锁), sync.Cond也算是另外的同步机制,控制着对共享资源的并发访问。
总结一下,在golang中,我们一般使用sync.WaitGroup进行并发协程的同步处理,同时会使用channel的关闭和Context(上下文)进行协程间的通知。
我们明天聊协程间数据的通信机制:channel
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END

















暂无评论内容