Golang中是否可以无限开辟协程以及如何控制协程的数量?

news2024/12/24 9:12:28

文章目录

  • 1. Golang中是否可以无限开辟协程?
  • 2. 不控制goroutine数量引发的问题
  • 3. 如何控制goroutine的数量?⭐️
    • 3.1 只用有buffer的channel
    • 3.2 channel与sync同步组合方式
    • 3.3 利用无缓冲channel与任务发送/执行分离方式

1. Golang中是否可以无限开辟协程?

首先我们在linux操作系统上运行以下这段程序,看会发生什么?

package main
  
import (
        "fmt"
        "math"
        "runtime"
)


// 测试是否可以无限go
func main(){
        // 模式业务需要开辟的数量
        task_cnt := math.MaxInt64
        
        for i := 0 ; i< task_cnt;i++ {
             go func (num int){
                 // 完成一些业务
                 fmt.Println("go func ",i," goroutine count=",runtime.NumGoroutine())
             }(i)
        }
}

程序运行在中途主进程直接被操作系统杀死,如下图所示:
请添加图片描述

2. 不控制goroutine数量引发的问题

我们知道goroutine具备轻量高效GPM调度的特点,如果无限开辟goroutine,短时间内会占用大量的占用操作系统的资源(文件描述符、CPU、内存等):

  • CPU浮动上涨;
  • 内存占用持续身高;
  • 主进程被操作系统杀死;

这些资源实际上是用户态程序共享的资源,所以大批的goroutine最终引发灾难不仅仅是自身,还会关联其他运行的程序。

3. 如何控制goroutine的数量?⭐️

3.1 只用有buffer的channel

例如使用一个有缓冲的channel。当channel满了的时候,其会发生阻塞,避免一直不断的开辟goroutine。其设计逻辑如下:
请添加图片描述
完整代码如下:

package main
  
import (
        "fmt"
        "math"
        "runtime"
)

func MyWork(c chan bool,i int){
        fmt.Println("go func ",i," goroutine count=",runtime.NumGoroutine())
        <- c
}

// 测试是否可以无限go
func main(){
        // 模式业务需要开辟的数量
        task_cnt := math.MaxInt64
        // 创建一个带缓冲的channel
        myChan := make(chan bool,3)

        // 循环创建业务
        for i := 0 ; i< task_cnt;i++ {
                myChan <- true
                go  MyWork(myChan,i)
        }
}

按照上面的方式使得能够一直运行。其实实际上,执行的只有3个(还有一个main goroutine)。上面代码的本质就是在myChan <- true处会阻塞,直到之前三个中有一个完成了任务,阻塞接触,才开辟一个新的goroutine。
请添加图片描述

3.2 channel与sync同步组合方式

  • 如果我们只使用sync的WaitGroup会怎么样?
    package main
      
    import (
            "fmt"
            "math"
            "runtime"
            "sync"
    )
    
    // 创建一个全局的wait_group{}
    var wg = sync.WaitGroup{}
    
    func MyWork(i int){
            fmt.Println("go func ",i," goroutine count=",runtime.NumGoroutine())
            wg.Done()
    }
    
    // 测试是否可以无限go
    func main(){
            // 模式业务需要开辟的数量
            task_cnt := math.MaxInt64
    
            // 循环创建业务
            for i := 0 ; i< task_cnt;i++ {
                    wg.Add(1)
                    go  MyWork(i)
            }
            // 阻塞等待
            wg.Wait()
    }
    
    
    结果是仍然无法大量开辟,主线程会被操作系统杀死。
    请添加图片描述
  • channel与sync同步组合方式
    package main
    
    import (
            "fmt"
            "math"
            "runtime"
            "sync"
    )
    
    // 创建一个sync.WaitGroup{}变量
    var wg = sync.WaitGroup{}
    
    func MyWork(c chan bool,i int){
            fmt.Println("go func ",i," goroutine count=",runtime.NumGoroutine())
            wg.Done()
            <- c
    }
    
    // 测试是否可以无限go
    func main(){
            // 模式业务需要开辟的数量
            task_cnt := math.MaxInt64
            // 创建一个带缓冲的channel
            myChan := make(chan bool,3)
    
            // 循环创建业务
            for i := 0 ; i< task_cnt;i++ {
                    wg.Add(1)
                    myChan <- true
                    go  MyWork(myChan,i)
            }
            wg.Wait()
    }
    

3.3 利用无缓冲channel与任务发送/执行分离方式

代码逻辑:

package main

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

// 定义一个WaitGroup类型的变量,保证所有的任务都能执行完毕
var wg = sync.WaitGroup{}

// 任务执行函数
func MyWork(c chan int){
	// 表示业务执行完毕
	defer wg.Done()
	for t := range c {
		// 模拟业务处理逻辑
		fmt.Println(t)
		
	}
}

// 发送业务的函数
func SendTask(c chan int,task int){
	// 保证所有的任务都能执行完毕
	wg.Add(1)
	c <- task
}

func main(){
	// 创建一个无缓冲的通道
	myChan := make(chan int)
	// 开辟固定数量的协程
	for i := 0; i < 3 ; i++ {
		go MyWork(myChan) // 他们都会各自内部阻塞,等待任务发送过来
	}
	// 最大任务数量
	task_cnt := math.MaxInt64
	// 开始发送任务
	for i := 0 ; i < task_cnt ; i++ {
		SendTask(myChan,i)
	}
	// 等待
	wg.Wait()
}

整体架构如下
请添加图片描述
这里实际上是将任务的发送和执行做了业务上的分离。使得输入SendTask的频率可设置、执行Goroutine的数量也可设置。也就是既控制输入(生产),又控制输出(消费)。使得可控更加灵活。这也是很多Go框架的Worker工作池的最初设计思想理念。

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

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

相关文章

腾讯轻联中多维表记录id是什么?如何获取记录id?

在腾讯文档智能表、金山轻维表、维格表需要去【更新表格数据】的时候&#xff0c;经常会需要输入记录id&#xff08;英文record id&#xff09;&#xff0c;很多用户也会有疑问&#xff0c;什么是记录id&#xff0c;如何获取记录id等。 金山、维格表、腾讯文档的记录ID是什么&a…

字节跳动CVPR 2023论文精选来啦(内含一批图像生成新研究)

计算机视觉领域三大顶会之一的 CVPR 今年已经开奖啦。 今年的 CVPR 将于六月在加拿大温哥华举办&#xff0c;和往年一样&#xff0c;字节跳动技术团队的同学们收获了不少中选论文&#xff0c;覆盖文本生成图像、语义分割、目标检测、自监督学习等多个领域&#xff0c;其中不少…

[ROC-RK3568-PC] [Firefly-Android] 10min带你了解Camera的使用

&#x1f347; 博主主页&#xff1a; 【Systemcall小酒屋】&#x1f347; 博主追寻&#xff1a;热衷于用简单的案例讲述复杂的技术&#xff0c;“假传万卷书&#xff0c;真传一案例”&#xff0c;这是林群院士说过的一句话&#xff0c;另外“成就是最好的老师”&#xff0c;技术…

SVN利用 AS 进行代码对比的方法

第 1 种&#xff1a;如果我们是从 SVN 检出的项目&#xff0c;并且想比较本地代码与从 SVN 检出时的代码相比都有那些区别&#xff0c;可以按如下步骤操作 如上图所示&#xff0c;在代码编辑区&#xff0c;右键唤出功能菜单&#xff0c;然后选择Subversion&#xff0c;进而会展…

沉浸式翻译 – 支持 PDF、EPUB、网页,可同时显示原文与译文的双语翻译工具

使用的理由 自从谷歌翻译不再对大陆用户提供服务后。内心是一阵酸痛的&#xff0c;毕竟我认识单词单词不认识我啊&#xff0c;这简直是天书一般的存在。 期间网络中的很多大神也是推荐了不少方法让我再次拥抱谷歌翻译&#xff0c;比如教我修改 host 文件什么的&#xff0c;但这…

谁能真正替代你?AI辅助编码工具深度对比(chatGPT/Copilot/Cursor/New Bing)

写在开头 这几个月AI相关新闻的火爆程度大家都已经看见了&#xff0c;作为一个被裹挟在AI时代浪潮中的程序员&#xff0c;在这几个月里我也是异常兴奋和焦虑。甚至都兴奋的不想拖更了。不仅仅兴奋于AI对于我们生产力的全面提升&#xff0c;也焦虑于Copilot等AI辅助编码工具&am…

VUE3 学习笔记(八-1)中 EasyUI 组件的使用方法

目录 一、首先看官方 Accordion 文档说明 二、如何使用 Props 属性 三、如何使用 Methods&#xff08;方法&#xff09; 四、如何使用Methods&#xff08;方法&#xff09; 1. 通过 ref 给Vue3中的标签添加引用 2. 在script setup lang"ts"中定义变量引用 3. 增…

全面剖析OpenAI发布的GPT-4比其他GPT模型强在哪里

最强的文本生成模型GPT-4一、什么是GPT-4二、GPT-4的能力三、和其他GPT模型比较3.1、增加了图像模态的输入3.2、可操纵性更强3.3、复杂任务处理能力大幅提升3.4、幻觉、安全等局限性的改善3.6、风险和缓解措施改善更多安全特性3.7、可预测的扩展四、与之前 GPT 系列模型比较五、…

边缘计算那些事儿—边缘智能技术

0 背景 边缘智能是边缘计算中一个非常重要的方向。它将边缘计算和人工智能算法结合起来&#xff0c;在边缘设备上就近处理目标检测、物体跟踪&#xff0c;识别等任务。这种处理方式可以降低时延&#xff0c;减少数据上送云端对回传网络的冲击&#xff0c;同时保证数据的隐私和安…

「线性DP-步入」最大子串和

最大子串和 题目描述 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 样例 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&…

计算机组成原理第五章输入输出系统---概述笔记

我们都知道,外部设备和计算机是不能直接相连的,因为设备是多种多样的&#xff0c;都是通过一个接口设备和主存相连的&#xff0c;主机对外部设备有两种控制方式&#xff0c;程序查询方式和程序中断方式&#xff0c;第三种是DMA方式&#xff0c;这三种方式都是从CPU工作效率的角…

HTML表单和CSS属性以及DOM实现网页版计算器

目录 1、效果展示 2、源码 2.1HTMLCSS源码 2.2JS源码 3、CSS属性 3.1width、height属性 3.2font-size属性 3.3margin属性 3.4padding属性 3.5background-color属性 3.6border属性 3.7border-radius属性 3.8text-align属性 4、DOM 4.1根据id获取元素 4.2根据nam…

06 - 深度学习处理器原理

一、通用计算机架构 1. 冯诺依曼架构 冯诺依曼架构的特点:(1)使用存储程序的概念,即数据和指令都存储在内存中;(2)由 CPU、内存、输入/输出设备和总线组成,其中 CPU 包括控制单元、算术逻辑单元和寄存器;(3)控制单元按照取指(Fetch)- 译码(Decode)- 执行(Exec…

IM即时通讯-7-如何设计通知提醒

本文大纲 本文从为什么做通知提醒&#xff0c; 以及如何设计通知提醒&#xff0c; 以及如何衡量通知提醒三方面解释了如何设计通知提醒。 对于重点的如何设计通知提醒&#xff0c; 通过拆分前台和后台&#xff0c; 前台采用自建或者二方通道&#xff0c; 后台采用厂商信令通道…

电厂人员定位怎么做?智慧电厂人员定位系统解决方案告诉你答案

伴随着“泛在电力物联网建设”的提出&#xff0c;构建智慧电厂引起重大关注&#xff0c;全国各地纷纷响应。传统电力企业一直面临着人员管控难、生产环境复杂且危险多等问题&#xff0c;物联网技术的兴起使得电厂的数字化和智慧化转型已成为电力企业保障生产作业安全、提升生产…

工具及方法 - Linux下串口工具Minicom

因为调试设备所以需要打开两个串口&#xff0c;也许是开了Ubuntu虚拟机的影响&#xff0c;或其他的问题&#xff0c;经常有一个或两个串口设备工作不正常&#xff0c;需要重启电脑&#xff0c;很麻烦。 原因大概就是设备驱动问题&#xff0c;比如使用MobaXterm这个工具&#x…

基于NXP iMX8M Mini处理器测试DPDK

By Toradex秦海 1). 简介 DPDK (Data Plane Development Kit) 软件是一组用户空间库和驱动程序&#xff0c;可加速在所有主要 CPU 架构上运行的网络数据包处理工作负载&#xff0c;以便提升整个网络数据服务的QoS。其最早由 Intel 大约 2010年创建&#xff0c;后由6WIND公司发…

赛事报名启动丨百度Apollo星火自动驾驶大赛开始报名啦!

作为汽车智能化、网联化的关键环节&#xff0c;自动驾驶成为全球科技界、产业界竞争的新赛道。随着人工智能、5G通信、激光雷达、高精地图等多项技术不断完善&#xff0c;自动驾驶的判断力和理解力得到了显著提升。为了推动自动驾驶技术的发展、加快人工智能技术的迭代&#xf…

超详细的ARM架构适配介绍!

超详细的ARM架构适配介绍&#xff01; - 掘金 本文主要介绍云联壹云平台如何适配ARM&#xff0c;并运行在ARM CPU架构的机器上。 背景介绍 1、平台服务运行架构 云联壹云平台采用容器化&#xff0c;分布式的架构运行在 Kubernetes&#xff08;K8s&#xff09;之上。下面是平…

小白轻松学Spring Cloud

在了解SpringCloud之前&#xff0c;我们先来大致了解下微服务这个概念吧。 传统单体架构 单体架构在小微企业比较常见&#xff0c;典型代表就是一个应用、一个数据库、一个web容器就可以跑起来。 可以从上图看出&#xff0c;单体架构基本上就是如上所说的&#xff1a;一个应用…