【Go】如何控制协程的最大并发数

【Go】如何控制协程的最大并发数

    • 摘要
    • 引入-并发编程时遇到问题
    • 使用channel限制并发数

摘要

本文将讲解在Go代码中如何使用channel来限制最大并发量。
作者水平有限,有任何问题欢迎在文章下方留言!

引入-并发编程时遇到问题

前两天搬砖时遇到一个需求,需要大量请求另外一个服务获取信息。于是我便启用了多个协程并发地去发送请求,写完自测了一波,一开始请求量小还好,当请求量一多,很多请求就开始失败了,报如下错误:socket: too many open files

出现这个报错是因为linux中某个进程打开文件数(句柄)已经达到上限,也就是说并发协程数量太多了。

下面就来讲讲如何在代码中使用channel来限制最大并发量。

2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:n err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files
2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:t err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files
2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:v err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files
2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:l err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files
2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:s err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files
2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:h err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files
2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:r err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files
2022-05-30T15:21:50.624+0800    ERROR   project_manage/organization_service.go:156      func:GetProjectSimpleList GetStaffBaseInfoApi engName:g err:Get "http://xxx": dial tcp x.xx.xx.xx:80: socket: too many open files

使用channel限制并发数

使用channel限制并发数原理非常简单,利用了Go中channel缓冲区满时,会阻塞写入。

基本逻辑如下:

  • 创建一个channel,缓冲区设置为你想要的最大并发数,比如100。
  • 每创建一个协程前,就往channel里写入一个数值,表示占位
  • 每当一个协程执行结束时,就从channel中读出一个数值,表示让位
  • 当当前同时在执行的协程达到最大并发数时,即channel的缓冲区被占满,此时新的协程要执行时,占位会被阻塞,直到有其他协程退出让位后,才会执行。

此方法原理简单,代码实现起来也简单,十分优雅。不过需要注意的是,在最大并发数未触及其他限制的情况下(比如上述的同时请求数量太多,进程打开的句柄数量受限等情况),最大并发数也并不是越多,程序执行的越快,关于这个问题的讨论后续可以再写一篇文章进行深入。

具体Go代码如下所示:

func GetInfo(idList []int) error {
	var wg sync.WaitGroup
  
	// 限制最大并发数为100
	limitGoroutine := make(chan int, 100)
  
  wg.Add(len(idList))
	for _, id := range idList {
    
    // 每启动一个协程,就往channel里写入一位数
		limitGoroutine <- 0
    
		go func() {
			// 并发请求获取信息
      // 存入数据库
			wg.Done()
      
      // 协程执行完退出时,就从channel里读一位数
			<-limitGoroutine
      
		}()
	}
	wg.Wait()
	return nil
}

你可能感兴趣的:(GO,golang,linux)