前言

开发过程中,如果不限制并发数,如下代码这种,可能直接造成服务器宕机,而且很多结果不会输出

[!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,确实是一个很好的方案,输出的结果也是按顺序输出的

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

协程池

这个就是一次性创建所有的协程,然后再根据大小来调用

参考

Copyright © d4m1ts 2023 all right reserved,powered by Gitbook该文章修订时间: 2022-01-19 11:43:22

results matching ""

    No results matching ""