携手创作,一起生长!这是我参与「日新方案 8 月更文挑战」的第21天,点击检查活动概况

协程

goroutine 是轻量级线程,调度由 Go 运行时进行办理的。Go 言语的并发操控首要运用关键字 go 敞开协程 goroutine。Go 协程(Goroutine)之间经过信道(channel)进行通讯,简略的说就是多个协程之间通讯的管道。信道能够避免多个协程访问共享内存时产生资源争抢的问题。语法格局:

// 普通函数创立 goroutine
go 函数名(参数列表)
//匿名函数创立 goroutine
go func(参数列表){
    //函数体
}(调用参数列表)

协程能够敞开多少个?是否有约束呢?

func testRoutine() {
    var wg sync.WaitGroup
    for i := 0; i < math.MaxInt32; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            fmt.Printf("并发数量:%d/n", i)
            time.Sleep(time.Second)
        }(i)
    }
    wg.Wait()
}

以上代码敞开了 math.MaxInt32个协程的并发,执行后能够看到成果直接 panic:“panic: too many concurrent operations on a single file or socket (max 1048575)”。整个并发操作超出了体系最大值。

使用 channel 控制并发数量

操控协程数量

sync 同步机制

运用 sync.WaitGroup 发动指定数量的协程 goroutine。

func testRoutine() {
    var wg = sync.WaitGroup{}
    taskCount := 5 // 指定并发数量
    for i := 0; i < taskCount; i++ {
        wg.Add(1)
        go func(i int) {
            fmt.Println("go func ", i)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

如果 taskcount 设置的很大超出了约束的,则其还是没有操控到并发数量。能够优化下设计,类似池的设计思维,经过答应最大连接数操控量,当超出了数量就需要等候开释,有空闲的连接的时分才能够继续执行。

func testRoutine() {
    task_chan := make(chan bool, 3) //100 为 channel长度
    wg := sync.WaitGroup{}
    defer close(task_chan)
    for i := 0; i < math.MaxInt; i++ {
        wg.Add(1)
        fmt.Println("go func ", i)
        task_chan <- true
        go func() {
                <-task_chan
                defer wg.Done()
        }()
    }
    wg.Wait()
}
  • 创立缓冲区大小为 3 的 channel,在没有被接纳的情况下,至多发送 3 个消息则被阻塞。经过 channel 操控每次并发的数量。
  • 敞开协程前,设置 task_chan <- true,若缓存区满了则阻塞
  • 协程使命执行完成后就开释缓冲区
  • 等候所有的并发都处理完毕后则函数完毕。其实能够不运用 sync.WaitGroup。因运用 channel 操控并发处理的使命数量能够不用运用等候并发处理完毕。

参考资料:

  • boilingfrog.github.io/2021/04/14/…