前言
开发过程中,如果不限制并发数,如下代码这种,可能直接造成服务器宕机,而且很多结果不会输出
[!TIP|style:flat] 很多结果不会输出,是因为主协程结束时,子协程也会终止掉。
func main() {
userCount := math.MaxInt64
for i := 0; i < userCount; i++ {
go func(i int) {
// 做一些各种各样的业务逻辑处理
fmt.Printf("go func: %d\n", i)
time.Sleep(time.Second)
}(i)
}
}
尝试chan
package main
import (
"fmt"
"math"
"time"
)
func out(i int, semaphore chan bool){
fmt.Printf("go func: %d\n", i)
// 释放通道
<- semaphore
time.Sleep(time.Second)
}
func main() {
semaphore := make(chan bool, 2)
userCount := math.MaxInt8
for i := 0; i < userCount; i++ {
// 占用通道
semaphore <- true
go out(i, semaphore)
}
}
确实可以2个协程并发,但是和上面结果一样,很多结果不会输出,是因为主协程结束时,子协程也会终止掉。
go func: 1
go func: 0
go func: 3
go func: 4
go func: 5
go func: 6
go func: 7
go func: 8
尝试sync
主要使用sync.WaitGroup{}
package main
import (
"fmt"
"math"
"sync"
"time"
)
var wg = sync.WaitGroup{}
func out(i int){
fmt.Printf("go func: %d\n", i)
time.Sleep(time.Second)
wg.Done()
}
func main() {
userCount := math.MaxInt8
for i := 0; i < userCount; i++ {
wg.Add(1)
go out(i)
}
// 等待全部执行完
wg.Wait()
}
所有结果都显示出来了,也就是说所有子协程都执行完了,但是没有控制并发数量
尝试chan+sync√
从上面2个可以看出,一个可以控制并发数量,另一个可以让所有子协程都执行完,所以结合一下,就能达到我们的目的了
package main
import (
"fmt"
"math"
"sync"
"time"
)
var wg = sync.WaitGroup{}
func out(i int, semaphone chan bool){
fmt.Printf("go func: %d\n", i)
time.Sleep(time.Second)
// 释放通道
<- semaphone
defer wg.Done()
}
func main() {
semaphone := make(chan bool, 2)
userCount := math.MaxInt8
for i := 0; i < userCount; i++ {
wg.Add(1)
// 占用通道
semaphone <- true
go out(i, semaphone)
}
// 等待全部执行完
wg.Wait()
}
结合一下,确实能达到我们想到的效果了!!!就是结果有点乱,一般来说不影响了
go func: 1
go func: 0
go func: 3
go func: 2
go func: 4
go func: 5
go func: 6
go func: 7
go func: 8
go func: 9
信号量Semaphore
和Python中的信号量一样,感觉是结合了chan+sync,确实是一个很好的方案,输出的结果也是按顺序输出的
https://github.com/EDDYCJY/gsema
package main import ( "fmt" "github.com/EDDYCJY/gsema" "math" "time" ) var semaphore = gsema.NewSemaphore(2) func out(i int){ fmt.Printf("go func: %d\n", i) time.Sleep(time.Second) defer semaphore.Done() } func main() { userCount := math.MaxInt8 for i := 0; i < userCount; i++ { semaphore.Add(1) go out(i) } semaphore.Wait() }
go func: 0 go func: 1 go func: 2 go func: 3 go func: 4 go func: 5 go func: 6 go func: 7 go func: 8 go func: 9
协程池
这个就是一次性创建所有的协程,然后再根据大小来调用
https://github.com/Jeffail/tunny
参考