前言
开发过程中,如果不限制并发数,如下代码这种,可能直接造成服务器宕机,而且很多结果不会输出
[!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 - 参考