Go 如何控制并发的goroutine数量?

为什么要控制goroutine并发的数量?

在开发过程中,如果不对goroutine加以控制而进行滥用的话,可能会导致服务整体崩溃。比如耗尽系统资源导致程序崩溃,或者CPU使用率过高导致系统忙不过来。

用什么方法控制goroutine并发的数量?

有缓冲channel

利用缓冲满时发送阻塞的特性

package main

import (
    "fmt"
    "runtime"
    "time"
)

var wg = sync.WaitGroup{}

func main() {
    // 模拟用户请求数量
    requestCount := 10
    fmt.Println("goroutine_num", runtime.NumGoroutine())
    // 管道长度即最大并发数
    ch := make(chan bool, 3)
    for i := 0; i < requestCount; i++ {
        wg.Add(1)
        ch <- true
        go Read(ch, i)
    }

     wg.Wait()
}

func Read(ch chan bool, i int) {
    fmt.Printf("goroutine_num: %d, go func: %d\n", runtime.NumGoroutine(), i)
    <-ch
    wg.Done()
}

输出结果:默认最多不超过3(4-1)个goroutine并发执行

goroutine_num 1
goroutine_num: 4, go func: 1
goroutine_num: 4, go func: 3
goroutine_num: 4, go func: 2
goroutine_num: 4, go func: 0
goroutine_num: 4, go func: 4
goroutine_num: 4, go func: 5
goroutine_num: 4, go func: 6
goroutine_num: 4, go func: 8
goroutine_num: 4, go func: 9
goroutine_num: 4, go func: 7

无缓冲channel

任务发送和执行分离,指定消费者并发协程数

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var wg = sync.WaitGroup{}

func main() {
    // 模拟用户请求数量
    requestCount := 10
    fmt.Println("goroutine_num", runtime.NumGoroutine())
    ch := make(chan bool)
    for i := 0; i < 3; i++ {
        go Read(ch, i)
    }

    for i := 0; i < requestCount; i++ {
        wg.Add(1)
        ch <- true
    }

    wg.Wait()
}

func Read(ch chan bool, i int) {
    for _ = range ch {
        fmt.Printf("goroutine_num: %d, go func: %d\n", runtime.NumGoroutine(), i)
        wg.Done()
    }
}

本文节选于Go合集《Go语言面试题精讲》
GOLANG ROADMAP 一个专注Go语言学习、求职的社区。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Golang中的并发编程使用goroutine和channel实现。Goroutine是一种轻量级的线程,可以在同一进程内并发地运行多个任务,而不会造成线程上下文切换的开销。Channel是一种特殊的数据类型,用于在不同的goroutine之间传递数据。 使用goroutine非常简单,只需要在函数调用前加上关键字go即可启动一个goroutine。例如: ``` func main() { go func() { // 这里是一个新的goroutine }() // 这里是主goroutine } ``` 使用channel也很简单,可以使用make函数创建一个channel,然后使用<-操作符发送或接收数据。例如: ``` ch := make(chan int) go func() { ch <- 42 // 发送数据 }() x := <-ch // 接收数据 ``` 在Golang中,channel的发送和接收操作是阻塞的。当发送者向一个已满的channel发送数据时,发送操作会被阻塞,直到有接收者从该channel中接收数据。同样地,当接收者从一个空的channel中接收数据时,接收操作也会被阻塞,直到有发送者向该channel中发送数据。 除了基本的发送和接收操作外,channel还支持以下操作: - 关闭通道:使用close函数关闭通道。关闭通道后,无法再发送数据,但可以继续接收数据。 - 判断通道是否已关闭:使用_, ok := <-ch语句判断通道是否已关闭。 - 使用带缓冲的通道:使用make函数创建一个带缓冲的通道,例如ch := make(chan int, 10)。带缓冲的通道可以存储一定数量的数据,当缓冲区已满时,发送操作会阻塞,直到有接收者从该通道中接收数据。 通过goroutine和channel的组合,Golang实现了高效的并发编程,这也是Golang的一大特色。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值