控制goroutine 的并发执行数量

goroutine的数量上限是1048575吗?


正常项目,协程数量超过十万就需要引起重视。如果有上百万goroutine,一般是有问题的。

但并不是说协程数量的上限是100多w

1048575的来自类似如下的demo代码:

package main

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

// https://zhuanlan.zhihu.com/p/568151296
func main() {

 maxCount := math.MaxInt64
 for i := 0; i < maxCount; i++ {
  go func(i int) {
   fmt.Printf("i is: %d,goroutine num: %d\n", i, runtime.NumGoroutine())

   // 模拟各种耗时较长的业务逻辑
   time.Sleep(10 * time.Second)

  }(i)
 }
}

执行后,很快报错

alt

panic: too many concurrent operations on a single file or socket (max 1048575)

但这个是因为fmt.Printf导致的:

对单个file/socket的并发操作数超过了系统上限,这个是标准输出造成的,具体一点,就是文件句柄数量达到限制

如下例子,去掉fmt:

package main

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

func main() {

 maxCount := math.MaxInt64
 for i := 0; i < maxCount; i++ {
  go func(i int) {
   // 模拟各种耗时较长的业务逻辑
   //time.Sleep(10 * time.Hour)
   time.Sleep(15 * time.Second)
   if i > 1300_0000 {
    //if runtime.NumGoroutine() > 1000_0000 {
    fmt.Println("当前协程数:", runtime.NumGoroutine())
   }

  }(i)
 }
}
alt

实际同一时间可以出现1000w的goroutine,可见goroutine的理论上限绝对不止100w

或者如下:

package main

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

func main() {

 maxCount := math.MaxInt64
 for i := 0; i < maxCount; i++ {
  go func(i int) {
   // 模拟各种耗时较长的业务逻辑
   //time.Sleep(10 * time.Hour)
   time.Sleep(15 * time.Second)
   //if i > 1300_0000 {
   if runtime.NumGoroutine() > 800_0000 {
    fmt.Println("当前协程数:", runtime.NumGoroutine())
   }

  }(i)
 }
}
alt
panic: too many concurrent operations on a single file or socket (max 1048575)

goroutine 1231546 [running]:
internal/poll.(*fdMutex).rwlock(0x140000a20600x20?)
        /Users/fliter/.g/go/src/internal/poll/fd_mutex.go:147 +0x134
internal/poll.(*FD).writeLock(...)
        /Users/fliter/.g/go/src/internal/poll/fd_mutex.go:239
internal/poll.(*FD).Write(0x140000a2060, {0x14635532bc00x190x20})
        /Users/fliter/.g/go/src/internal/poll/fd_unix.go:370 +0x48
os.(*File).write(...)
        /Users/fliter/.g/go/src/os/file_posix.go:48
os.(*File).Write(0x140000a0008, {0x14635532bc0?, 0x190x10412e25c?})
        /Users/fliter/.g/go/src/os/file.go:175 +0x60
fmt.Fprintln({0x104168cf80x140000a0008}, {0x140bde92f880x20x2})
        /Users/fliter/.g/go/src/fmt/print.go:285 +0x74
fmt.Println(...)
        /Users/fliter/.g/go/src/fmt/print.go:294
main.main.func1(0x0?)
        /Users/fliter/go/src/shuang/0000/goNum.go:20 +0x150
created by main.main
        /Users/fliter/go/src/shuang/0000/goNum.go:14 +0x54
exit status 2

比较奇怪的是,如果将模拟各种耗时较长的业务逻辑time.Sleep(15 * time.Second)改为time.Sleep(10 * time.Hour),最终会因为内存过高而signal: killed。但此时goroutine数量不够多,触发不了if里面的fmt逻辑,故而不会出现panic: too many concurrent operations on a single file or socket (max 1048575)

alt

(而休眠10几s的代码,内存到不了这么大,就已经因为fmt的问题panic了)

alt

控制方式


使用有缓冲的channel,限制并发的协程数量


make(chan struct{}, 300) 创建缓冲区大小为 300 的 channel,在没有被接收的情况下,至多发送 300 个消息则被阻塞。

开启协程前,调用 ch <- struct{}{},若缓存区满,则阻塞。 协程任务结束,调用 <-ch 释放缓冲区。

// 通过channel来控制并发数

package main

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

func main() {

 ch := make(chan struct{}, 300)
 maxCount := math.MaxInt64
 for i := 0; i < maxCount; i++ {
  ch <- struct{}{}
  go func(i int) {
   //fmt.Printf("i is: %d,go func num: %d\n", i, runtime.NumGoroutine())

   // 模拟各种耗时较长的业务逻辑
   //time.Sleep(10 * time.Hour)
   time.Sleep(15 * time.Second)
   //if i > 1000_0000 {
   //if runtime.NumGoroutine() > 1000_0000 {
   fmt.Println("当前协程数:", runtime.NumGoroutine())
   //}

   //读取channel数据
   <-ch

  }(i)
 }
}
当前协程数: 301
当前协程数: 301
当前协程数: 301
当前协程数: 301
当前协程数: 301
当前协程数: 301
当前协程数: 301
当前协程数: 301
当前协程数: 301
...

同时只有301个协程(每15s,处理301个;限制太少,会大大增加程序执行完成需要的时间,具体限制多少,需要权衡,太大太小可能都有问题)


更多参考:

如何控制golang协程的并发数量问题[1]

golang实现并发数控制的方法[2]

golang控制并发数[3]

Golang的并发控制[4]


即所谓的

无缓冲的channel可以当成阻塞锁来使用 (Go用两个协程交替打印100以内的奇偶数)

有缓冲的channel通常可以用来控制goroutine的数量


来,控制一下 goroutine 的并发数量[5]

还有通过协程池,信号量等方式,可参考 【警惕】请勿滥用goroutine[6]

aceld-Go是否可以无限go?如何限定数量?[7]

参考资料

[1]

如何控制golang协程的并发数量问题: http://www.manongjc.com/detail/62-ixfkirkdenvuohr.html

[2]

golang实现并发数控制的方法: http://www.qb5200.com/article/327027.html

[3]

golang控制并发数: https://blog.csdn.net/weixin_38155824/article/details/128240704

[4]

Golang的并发控制: https://blog.csdn.net/LINZEYU666/article/details/123020597

[5]

来,控制一下 goroutine 的并发数量: https://eddycjy.gitbook.io/golang/di-1-ke-za-tan/control-goroutine

[6]

【警惕】请勿滥用goroutine: https://juejin.cn/post/6999807716482875422#heading-5

[7]

aceld-Go是否可以无限go?如何限定数量?: https://github.com/catandcoder/golang/blob/main/4%E3%80%81Go%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E6%97%A0%E9%99%90go%EF%BC%9F%E5%A6%82%E4%BD%95%E9%99%90%E5%AE%9A%E6%95%B0%E9%87%8F%EF%BC%9F.md

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/61698.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023-08-31力扣每日一题-姜汁水题

链接&#xff1a; 1761. 一个图中连通三元组的最小度数 题意&#xff1a; 选择两两相连的三个点&#xff0c;要求度最小 解&#xff1a; 什么暴力hard 实际代码&#xff1a; #include<bits/stdc.h> using namespace std; int minTrioDegree(int n, vector<vect…

使用 Nginx 搭建文件下载服务器

文章目录 一、基础环境二、适用场景三、方法和步骤四、其他说明 版权声明&#xff1a;本文为CSDN博主「杨群」的原创文章&#xff0c;遵循 CC 4.0 BY-SA版权协议&#xff0c;于2023年8月27日首发于CSDN&#xff0c;转载请附上原文出处链接及本声明。 原文链接&#xff1a;http…

CXL 内存交织(Memory Interleaving)

&#x1f525;点击查看精选 CXL 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0c…

Web后端开发(请求响应)上

请求响应的概述 浏览器&#xff08;请求&#xff09;<--------------------------(HTTP协议)---------------------->&#xff08;响应&#xff09;Web服务器 请求&#xff1a;获取请求数据 响应&#xff1a;设置响应数据 BS架构&#xff1a;浏览器/服务器架构模式。…

uniapp项目实战系列(3):底部导航栏与头部导航栏的配置

目录 系列往期文章&#xff08;点击跳转&#xff09;uniapp项目实战系列(1)&#xff1a;导入数据库&#xff0c;启动后端服务&#xff0c;开启代码托管&#xff08;点击跳转&#xff09;uniapp项目实战系列(2)&#xff1a;新建项目&#xff0c;项目搭建&#xff0c;微信开发工具…

33、Flink之hive介绍与简单示例

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

微信小程序使用本地存储方法wx.setStorageSync()和wx.getStorageSync()

微信小程序的本地存储可以使用wx.setStorageSync()和wx.getStorageSync()方法实现 使用wx.setStorageSync()方法可以将数据以键值对的方式存储到本地存储中&#xff1a; wx.setStorageSync(demo, demo123);获取数据&#xff1a;使用wx.getStorageSync()方法可以从本地存储中获…

「MySQL-05」MySQL Workbench的下载和使用

目录 一、MySQL workbench的下载和安装 1. MySQL workbench介绍 2. 到MySQL官网下载mysql workbench 3. 安装workbench 二、创建能远程登录的用户并授权 1. 创建用户oj_client 2. 创建oj数据库 3. 给用户授权 4. 在Linux上登录用户oj_client检查其是否能操作oj数据库 三、使用…

OpenCV(六):多通道分离与合并

目录 1.多通道分离split() 2.多通道合并merge() 3.Android JNI demo 1.多通道分离split() void cv::split ( InputArray m, OutputArrayOfArrays mv &#xff09; m:待分离的多通道图像。 mv:分离后的单通道图像&#xff0c;为向量vector形式。 2.多通道合并merge…

C++ 友元

朋友可访问自己的东西&#xff0c;大概就这么个意思。即某类的友元类可访问该类的所有变量以及函数&#xff0c;或友元函数可以访问该类的变量以及函数&#xff0c;在朋友眼中没有任何隐藏&#xff0c;可谓时赤裸相对&#xff0c;肝胆相照&#xff0c;生生挚友。 注意&#xf…

聊聊检索增强,LangChain一把梭能行吗?

背景 ChatGPT诞生之初&#xff0c;大家仿佛从中看到了未来&#xff1a;可以拿着大语言模型&#xff08;LLM&#xff09;这把锤子&#xff0c;锤遍业务上的钉子。其中最被看好的场景&#xff0c;莫过于搜索&#xff0c;不仅是微软、谷歌、百度这样的大公司将LLM用到自己的搜索业…

ROS2学习(一):Ubuntu 22.04 安装 ROS2(Iron Irwini)

文章目录 一、ROS2(Iron Irwini)介绍二、ROS2(Iron Irwini)安装1.设置编码2.使能代码库3.安装ROS2 Iron 三、ROS2测试四、ROS2卸载 一、ROS2(Iron Irwini)介绍 官方文档 Iron Irwini版本支持的平台如下&#xff1a; 二、ROS2(Iron Irwini)安装 1.设置编码 sudo apt update…

利用python爬取谷歌趋势某个关键词的每日搜索次数

大家好&#xff0c;我是带我去滑雪&#xff01;本期尝试利用python爬取谷歌趋势某个关键词的每日搜索次数。 目录 1、什么是谷歌趋势&#xff1f; 2、爬取谷歌趋势的搜索次数有何用&#xff1f; 3、代码如何实现&#xff1f; (1&#xff09;导入相关模块 &#xff08;2&a…

Java实现根据关键词搜索京东商品列表数据方法,当当API接口(jd.item_search)申请指南

要通过京东网的API获取商品列表数据&#xff0c;您可以使用京东开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例&#xff0c;展示如何通过京东开放平台API获取商品列表&#xff1a; 首先&#xff0c;确保您已注册成为当当开放平台的开发者&#xff0c;并创建…

Windows安装单节点Zookeeper

刚学习Dubbo&#xff0c;在Centos7中docker安装的zookeeper3.7.1。然后在启动provider时一直报错&#xff0c;用尽办法也没有解决。然后zookeeper相关的知识虽然以前学习过&#xff0c;但是已经忘记的差不多了。现在学习dubbo只能先降低版本使用了&#xff0c;之后再复习zookee…

spring cloud新版本使用loadbalancer替代Ribbon

Nacos 2021 不再集成 Ribbon&#xff0c;建议使用spring cloud loadbalancer 引入 一、简单使用 引入依赖spring cloud loadbalancer <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer<…

数据库锁简析

数据库大并发操作要考虑死锁和锁的性能问题。用T1代表一个数据库执行请求&#xff0c;T2代表另一个请求&#xff0c;也可以理解为T1为一个线程&#xff0c;T2 为另一个线程。T3,T4以此类推。下面以SQL Server为例。 锁的种类 共享锁(Shared lock) 例1&#xff1a;T1: select…

Golang数据结构和算法

Golang数据结构和算法 数据的逻辑结构和物理结构常见数据结构及其特点算法的时间复杂度和空间复杂度Golang冒泡排序Golang选择排序Golang插入排序Golang快速排序Golang归并排序Golang二分查找Golang sort包Golang链表Golang container/list标准库Golang栈stackGolang二叉搜索树…

解决css样式中last-child不生效的问题

需求 项目中需要使用v-for指令来渲染一个图片列表&#xff0c; 现状 发现&#xff0c;最后一个格子并没有跟下面绿色线对齐。 最后发现 是因为 每个格子都给了 margin-right&#xff1a;36px&#xff0c;影响到了最后一个格子 所以使用last-child 将最后一个格子的margin 属性…

ARM DIY(六)音频调试

前言 今天&#xff0c;调试一下音频 硬件焊接 硬件部分核心是 LM4871 音频功放芯片 对于 SOC 来讲很简单&#xff0c;就一个引脚 HPOUTL&#xff08;单声道&#xff09;&#xff1b;对于扬声器来讲也很简单&#xff0c;就两个引脚&#xff0c;插上就可以了。 另外一个关键点…