谁把年华错落成诗 - 并发
type: channel
link: https://blog.pomears.com/tag/%E5%B9%B6%E5%8F%91/
items: Go使用WaitGroup与channel控制goroutine数量
items: Go 并发控制

Go使用WaitGroup与channel控制goroutine数量
type: item
date: 2020-04-30T11:33:00+08:00
description: 要点带缓存的channelWaitGroup示例func main() { // goroutine同时运行数量 ch := make(chan bool, 5) var synWait sync.WaitGroup // 执行总数量 count := 10 for i := 0; i < count; i++ { synWait.Add(1) ch <- true go func() { time.Sleep(time.Second) fmt.Println(time.Now().Format("2006-01-02 15:04:05")) <-ch synWait.Done() }() } synWait.Wait() } 打印的结果为2020-04-30 11:31:31 2020-04-30 11:31:31 2020-04-30 11:31:31 2020-04-30 11:31:31 2020-04-30 11:31:31 2020-04-30 11:31:32 2020-04-30 11:31:32 2020-04-30 11:31:32 2020-04-30 11:31:32 2020-04-30 11:31:32可见一秒执行了5次，正好为channel控制的同时goroutine数量

Go 并发控制
type: item
date: 2019-12-28T01:59:00+08:00
description: Go语言的并发，就不得不提goroutine，其作为Go语言的一大特色，在日常开发中使用很多Go goroutine理解这里就不对goroutine进行描述了，直接进入正文go并发控制方法主要有：公共变量channelWaitGroupcontext公共变量这是并发控制最简单的实现方式声明一个公共变量所有子goroutine共享这个变量，并不断轮询这个变量并检查是否有更新在主进程中变更该公共变量子goroutine检测到公共变量更新，执行相应的逻辑package main import ( "fmt" "time" ) func main() { // 公共变量 state := true go func(){ for state { println("goroutine A running") time.Sleep(1 * time.Second) } println("goroutine A exit") }() go func() { for state { println("goroutine B running") time.Sleep(1 * time.Second) } println("goroutine B exit") }() time.Sleep(2 * time.Second) state = false time.Sleep(2 * time.Second) fmt.Println("main func exit") }输出结果goroutine B running goroutine A running goroutine A running goroutine B running goroutine B running goroutine A running goroutine A exit goroutine B exit main func exit这种实现方式比较简单，但如果逻辑过于复杂，则变量不容易控制channelchannel是goroutine之间主要的通讯方式，一般会和select搭配使用Go channel 实现原理分析channel在这里也不做过多描述，大致处理过程为：声明一个可以判断结束的chan在goroutine中，使用select判断chan接收到的值。如果接收到结束，就可以走结束逻辑。如果没有，那么就会执行预设的逻辑，或者default主程序发送了结束的指令后子goroutine接到结束指令，进行结束逻辑package main import ( "fmt" "time" ) func main() { // 初始化一个接收bool的channel c := make(chan bool) go func() { for { select { case <- c: fmt.Println("goroutine exit") return default: fmt.Println("goroutine running.") } time.Sleep(100 * time.Millisecond) } }() time.Sleep(1 * time.Second) c <- false fmt.Println("main fun exit") }输出结果goroutine running. goroutine running. goroutine running. goroutine running. goroutine running. goroutine running. goroutine running. goroutine running. goroutine running. goroutine running. goroutine exit main fun exit这种方法比较优雅，但稍微复杂如果要控制多个goroutine，或者goroutine嵌套，就比较麻烦WaitGroupGo语言提供同步包syncsync包同步提供基本的同步原语，如互斥锁。除了Once和WaitGroup类型之外，大多数类型都是供低级库例程使用的。通过Channel和沟通可以更好地完成更高级别的同步。并且此包中的值在使用过后不要拷贝。Sync.WaitGroup是一种实现并发控制方式，WaitGroup 对象内部有一个计数器，最初从0开始，它有三个方法：Add(), Done(), Wait() 用来控制计数器的数量。Add(n) 把计数器设置为nDone() 每次把计数器-1wait() 会阻塞代码的运行，直到计数器地值减为0package main import ( "fmt" "sync" "time" ) func main() { fmt.Println(time.No…