控制并发数量可以避免服务器奔溃:以下方式尝试控制
注意:多个并发协程之间不需要通信,那么就可以使用 sync.WaitGroup
如果并发启动了多个子协程,需要等待所有的子协程完成任务,WaitGroup 非常适合于这类场景
- 只是用Chan控制
package main
import (
"fmt"
)
//控制并发数量 chan
func main() {
count := 10
ch := make(chan bool, 2)
for i := 0; i < count; i++ {
ch <- true
go read(ch, i)
}
//time.Sleep(time.Second * 2)
}
func read(ch chan bool, i int) {
fmt.Println("第", i, "个协程",time.Now().Unix())
//为了测试并发数量
time.Sleep(time.Second)
<-ch
}
/* 以下为输出---(应该输出10个)
第 1 个协程 1663071133
第 0 个协程 1663071133
第 2 个协程 1663071134
第 3 个协程 1663071134
第 4 个协程 1663071135
第 5 个协程 1663071135
第 6 个协程 1663071136
第 7 个协程 1663071136
第 8 个协程 1663071137
*/
出现问题:看似达到控制2个2个输出的效果,但是主协程结束时,子协程也是会被终止掉的,因此剩余的 goroutine 没来及把值输出,
- 只使用Sync.WaitGroup
// Sync控制
var wg sync.WaitGroup
func main() {
count := 10
for i := 0; i < count; i++ {
wg.Add(1)
go read(i)
}
wg.Wait()
}
func read(i int) {
defer wg.Done()
fmt.Println("第", i, "个协程", time.Now().Unix())
//为了测试并发数量
time.Sleep(time.Second)
}
/* 以下为输出---(应该输出10个)
第 9 个协程 1663070879
第 4 个协程 1663070879
第 2 个协程 1663070879
第 3 个协程 1663070879
第 0 个协程 1663070879
第 6 个协程 1663070879
第 5 个协程 1663070879
第 7 个协程 1663070879
第 8 个协程 1663070879
第 1 个协程 1663070879
*/
出现问题:没有达到控制2个2个输出的效果。
- 使用Sync.WaitGroup+Chan
//Sync+Chan
var wg sync.WaitGroup
func main() {
count := 10
ch := make(chan bool, 2)
for i := 0; i < count; i++ {
wg.Add(1)
ch <- true
go read(ch, i)
}
wg.Wait()
}
func read(ch chan bool, i int) {
defer wg.Done()
//TODO
//ch <- true 放在里面吃内存(待处理 )
fmt.Println("第", i, "个协程", time.Now().Unix())
//为了测试并发数量
time.Sleep(time.Second)
<-ch
}
/* 以下为输出---(应该输出10个)
第 1 个协程 1663071133
第 0 个协程 1663071133
第 2 个协程 1663071134
第 3 个协程 1663071134
第 4 个协程 1663071135
第 5 个协程 1663071135
第 6 个协程 1663071136
第 7 个协程 1663071136
第 8 个协程 1663071137
*/
成功:达到控制2个2个输出的效果。
新场景——控制输入的数量,以此达到改变允许并发运行 goroutine 的数量(灵活控制)
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var count int
func main() {
userCount := 10
ch := make(chan int, 5)
for i := 0; i < userCount; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for d := range ch {
count++
fmt.Println("第", count, "个协程", time.Now().Unix())
time.Sleep(time.Second * time.Duration(d))
}
}()
}
for i := 0; i < 10; i++ {
//输入几个ch 就有几个*userCount个协程
ch <- 1
ch <- 2
ch <- 3
//time.Sleep(time.Second)
}
close(ch)
wg.Wait()
}
/* 以下为输出---(应该输出30个)
第 1 个协程 1663072405
第 2 个协程 1663072405
第 4 个协程 1663072405
第 5 个协程 1663072405
第 6 个协程 1663072405
第 7 个协程 1663072405
第 8 个协程 1663072405
第 9 个协程 1663072405
第 10 个协程 1663072405
第 3 个协程 1663072405
第 12 个协程 1663072406
第 13 个协程 1663072406
第 14 个协程 1663072406
第 11 个协程 1663072406
第 15 个协程 1663072407
第 16 个协程 1663072407
第 17 个协程 1663072407
第 18 个协程 1663072407
第 19 个协程 1663072408
第 20 个协程 1663072408
第 21 个协程 1663072408
第 22 个协程 1663072408
第 23 个协程 1663072408
第 24 个协程 1663072408
第 25 个协程 1663072409
第 26 个协程 1663072409
第 28 个协程 1663072409
第 27 个协程 1663072409
第 29 个协程 1663072410
第 30 个协程 1663072410
*/