golang实现并发控制的方法和技巧

 更新时间:2024年03月05日 09:40:55   作者:嘻嘻爱编码  
golang 是一门支持并发的编程语言,它提供了 goroutine 和 channel 等强大的特性,让我们可以轻松地创建和管理多个执行单元,实现高效的任务处理,在本文中,我们将介绍一些 golang 的并发控制的方法和技巧,希望对你有所帮助

前言

golang 是一门支持并发的编程语言,它提供了 goroutine 和 channel 等强大的特性,让我们可以轻松地创建和管理多个执行单元,实现高效的任务处理。但是,并发也带来了一些挑战,比如如何控制 goroutine 的数量,如何避免资源竞争,如何保证数据的一致性等。在本文中,我们将介绍一些 golang 的并发控制的方法和技巧,希望对你有所帮助。

为什么要控制 goroutine 的数量

goroutine 是 golang 中最基本的执行单元,它是一种轻量级的线程,可以在一个或多个系统线程上运行。goroutine 的创建和调度都不需要进入内核,因此开销很小,我们可以轻松地创建上百万个而不会导致系统资源耗尽。那么,我们是不是可以随心所欲地使用 goroutine,而不用担心它的数量呢?

答案是否定的。虽然 goroutine 很轻量,但它也不是免费的,它也会占用一定的内存空间,每个 goroutine 至少需要 2KB 的栈空间,如果 goroutine 的数量过多,就会导致内存不足,甚至触发频繁的垃圾回收,影响程序的性能。另外,goroutine 也会消耗 CPU 的时间片,如果 goroutine 的数量超过 CPU 的核心数,就会导致上下文切换,增加 CPU 的负担。因此,我们在使用 goroutine 的时候,需要根据实际的场景和需求,合理地控制 goroutine 的数量,避免过度并发。

如何控制 goroutine 的数量

那么,我们如何控制 goroutine 的数量呢?有没有什么通用的方法或者技巧呢?其实,golang 本身就提供了一些并发控制的机制,比如 channel 和 sync 包,我们可以利用它们来实现 goroutine 的数量限制。下面,我们就来看一些具体的例子。

利用 channel 的缓冲区

channel 是 golang 中实现并发通信的重要工具,它可以在不同的 goroutine 之间传递数据,实现同步和协作。channel 有两种类型,一种是无缓冲的 channel,另一种是有缓冲的 channel。无缓冲的 channel 是同步的,发送和接收操作必须同时发生,否则会阻塞。有缓冲的 channel 是异步的,它有一个固定大小的缓冲区,可以存储一定数量的数据,发送操作只有在缓冲区满的时候才会阻塞,接收操作只有在缓冲区空的时候才会阻塞。

我们可以利用有缓冲的 channel 的特性,来实现 goroutine 的数量限制。具体的思路是,我们创建一个有缓冲的 channel,缓冲区的大小就是我们想要限制的 goroutine 的数量。然后,我们在启动一个 goroutine 之前,先向 channel 发送一个空结构体,如果 channel 满了,就会阻塞,直到有其他 goroutine 退出,从 channel 接收一个空结构体,释放缓冲区。这样,我们就可以保证同时运行的 goroutine 的数量不会超过 channel 的缓冲区大小。下面是一个简单的例子:

package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
func main() {
    var wg sync.WaitGroup
    ch := make(chan struct{}, 3) // 创建一个缓冲区大小为 3 的 channel
    for i := 0; i < 10; i++ {
        ch <- struct{}{} // 向 channel 发送一个空结构体,如果 channel 满了,就会阻塞
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            fmt.Println(i) // 做一些业务逻辑处理
            time.Sleep(time.Second)
            <-ch // 从 channel 接收一个空结构体,释放缓冲区
        }(i)
    }
    wg.Wait()
}

运行结果如下:

0
1
2
3
4
5
6
7
8
9

从结果中可以看到,每秒钟只并发执行了 3 个 goroutine,达到了我们的目的。这种方法的优点是简单易用,缺点是需要手动管理 channel 的发送和接收,如果忘记了,就会导致 goroutine 泄露或者死锁。

利用 sync 包

sync 包是 golang 提供的一个并发同步的包,它提供了一些常用的同步原语,比如互斥锁,条件变量,等待组等。其中,等待组(WaitGroup)是一个非常有用的工具,它可以用来等待一组 goroutine 的完成。WaitGroup 对象内部有一个计数器,最初从 0 开始,它有三个方法:Add,Done,Wait。Add 方法用来增加计数器的值,Done 方法用来减少计数器的值,Wait 方法用来阻塞,直到计数器的值为 0。

我们可以利用 WaitGroup 来实现 goroutine 的数量限制。具体的思路是,我们创建一个 WaitGroup 对象,然后在启动一个 goroutine 之前,先调用 Add 方法,增加计数器的值,如果计数器的值达到了我们想要限制的 goroutine 的数量,就会阻塞,直到有其他 goroutine 结束,调用 Done 方法,减少计数器的值,解除阻塞。这样,我们就可以保证同时运行的 goroutine 的数量不会超过我们设定的值。下面是一个简单的例子:

package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
func main() {
    var wg sync.WaitGroup
    limit := 3 // 限制 goroutine 的数量为 3
    for i := 0; i < 10; i++ {
        wg.Add(1) // 增加计数器的值,如果计数器的值达到 limit,就会阻塞
        go func(i int) {
            defer wg.Done()
            fmt.Println(i) // 做一些业务逻辑处理
            time.Sleep(time.Second)
        }(i)
        if i >= limit {
            wg.Wait() // 等待其他 goroutine 结束,减少计数器的值,解除阻塞
        }
    }
    wg.Wait()
}

运行结果如下:

0
1
2
3
4
5
6
7
8
9

从结果中可以看到,每秒钟只并发执行了 3 个 goroutine,达到了我们的目的。这种方法的优点是不需要额外的 channel,缺点是需要手动管理 WaitGroup 的 Add 和 Done 方法,如果忘记了,也会导致 goroutine 泄露或者死锁。

总结

在本文中,我们介绍了为什么要控制 goroutine 的数量,以及如何使用 golang 的 channel 和 sync 包来实现 goroutine 的数量限制。这些方法都是基于 golang 的并发特性,不需要引入第三方的库或者框架,可以方便地应用在实际的项目中。当然,这些方法并不是唯一的,也不一定是最优的,你可以根据你的具体的场景和需求,选择合适的方法,或者自己设计更好的方法,来实现 goroutine 的数量限制。

以上就是golang实现并发控制的方法和技巧的详细内容,更多关于golang并发控制的资料请关注脚本之家其它相关文章!

相关文章

  • go语言环境变量设置全过程

    go语言环境变量设置全过程

    这篇文章主要介绍了go语言环境变量设置全过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • Golang并发绕不开的重要组件之Goroutine详解

    Golang并发绕不开的重要组件之Goroutine详解

    Goroutine、Channel、Context、Sync都是Golang并发编程中的几个重要组件,这篇文中主要为大家介绍了Goroutine的相关知识,需要的可以参考一下
    2023-06-06
  • Golang加权轮询负载均衡的实现

    Golang加权轮询负载均衡的实现

    负载均衡器在向后端服务分发流量负载时可以使用几种策略。本文主要介绍了Golang加权轮询负载均衡,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • Go设计模式之单例模式图文详解

    Go设计模式之单例模式图文详解

    单例模式是一种创建型设计模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点,本文就通过图文给大家介绍一下Go的单例模式,需要的朋友可以参考下
    2023-07-07
  • golang 常用定时任务汇总

    golang 常用定时任务汇总

    这篇文章主要介绍了golang 常用定时任务汇总,golang利用goroutine外加github.com/gorhill/cronexpr库就可实现定时任务,具体代码介绍,需要的小伙伴可以参考一下
    2022-09-09
  • Go语言并发之Select多路选择操作符用法详解

    Go语言并发之Select多路选择操作符用法详解

    Go 语言借用多路复用的概念,提供了 select 关键字,用于多路监听多个通道,本文就来和大家聊聊Go语言中Select多路选择操作符的具体用法,希望对大家有所帮助
    2023-06-06
  • Gin框架使用panic处理中间件问题详解

    Gin框架使用panic处理中间件问题详解

    这篇文章主要介绍了Gin框架使用panic处理中间件问题,在 Gin 框架中,错误处理和 panic 处理是非常重要的功能。当处理 HTTP 请求时,可能会出现各种各样的错误,例如数据库连接错误、网络错误、权限问题等等
    2023-04-04
  • 浅谈Go语言的空标示符

    浅谈Go语言的空标示符

    本文通过文字及实例介绍了Go语言的空标示符,对此有不明白的朋友可以参考学习,下面一起来看看吧。
    2016-08-08
  • go grpc安装使用教程

    go grpc安装使用教程

    gRPC是由Google主导开发的RPC框架,使用HTTP/2协议并用ProtoBuf作为序列化工具。这篇文章主要介绍了go grpc安装使用教程,需要的朋友可以参考下
    2018-02-02
  • Go语言清除文件中空行的方法

    Go语言清除文件中空行的方法

    这篇文章主要介绍了Go语言清除文件中空行的方法,实例分析了Go语言针对文件的操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02

最新评论