用syc.WaitGroup来等待go协程执行完毕, 顺便看看协程并发数的控制方法

本文主要是介绍用syc.WaitGroup来等待go协程执行完毕, 顺便看看协程并发数的控制方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        看程序:

package mainimport ("fmt""time"
)func print(i int) {time.Sleep(1e9)fmt.Println(i)
}func main() {for i := 0; i < 10; i++ {go func(n int) {print(n)}(i)}
}

         结果没有任何输出,因为主协程很快退出了。

         等待一下,变为:

package mainimport ("fmt""time"
)func print(i int) {time.Sleep(1e9)fmt.Println(i)
}func main() {for i := 0; i < 10; i++ {go func(n int) {print(n)}(i)}for {}
}

         结果:

7
9
3
4
5
8
0
6
1
2

 

       这种等待太傻了, 改为:

package mainimport ("fmt""sync""time"
)func print(i int) {time.Sleep(1e9)fmt.Println(i)
}func main() {var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(n int) {defer wg.Add(-1)  // same: defer wg.Done()print(n)}(i)}wg.Wait() 
}

         结果:

8
1
5
0
9
4
7
2
6
3

       分析一下wg.Wait执行等待操作, 直到wg的计数变为0才返回。 在上面例子中,Add(1)了10次, 然后Add(-1)了10次,刚好。 我们把程序变一下:

package mainimport ("fmt""sync""time"
)func print(i int) {time.Sleep(1e9)fmt.Println(i)
}func main() {var wg sync.WaitGroupwg.Add(11)for i := 0; i < 10; i++ {go func(n int) {defer wg.Add(-1)  // same: defer wg.Done()print(n)}(i)}wg.Wait() 
}

        可以看到,计数达到11次,但只有10次的add(-1), 显然wg.Wait永远无法退出,提示:fatal error: all goroutines are asleep - deadlock!

        再看:

package mainimport ("fmt""sync""time"
)func print(i int) {time.Sleep(1e9)fmt.Println(i)
}func main() {var wg sync.WaitGroupwg.Add(5)for i := 0; i < 10; i++ {go func(n int) {defer wg.Add(-1)  // same: defer wg.Done()print(n)}(i)}wg.Wait() 
}

        结果出错,提示信息:

panic: sync: WaitGroup is reused before previous Wait has returned

panic: sync: negative WaitGroup counter

        看到没, negative counter了。

 

        最后,来看看协程并发数目的控制。 假设有102个离线任务需要并发执行,难道要开102个协程吗? 来看看怎么控制:

package mainimport ("fmt""sync""time"
)func print(i int) {time.Sleep(1e9)
}func main() {var wg sync.WaitGroupbegin := time.Now().Unix()j := 0for i := 0; i < 102; i++ {wg.Add(1)go func(n int) {defer wg.Add(-1) print(n)}(i)j++if j == 10 {wg.Wait()j = 0}}wg.Wait() end := time.Now().Unix()fmt.Println(end - begin)
}

         分析下结果, 不难得知, 结果为11. 运行了一下, OK. 

         另外,要注意,即使写连续写多个wg.Wait,也没有问题。

         不多说。

 

 

这篇关于用syc.WaitGroup来等待go协程执行完毕, 顺便看看协程并发数的控制方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/684045

相关文章

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

Java实现远程执行Shell指令

《Java实现远程执行Shell指令》文章介绍使用JSch在SpringBoot项目中实现远程Shell操作,涵盖环境配置、依赖引入及工具类编写,详解分号和双与号执行多指令的区别... 目录软硬件环境说明编写执行Shell指令的工具类总结jsch(Java Secure Channel)是SSH2的一个纯J

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

504 Gateway Timeout网关超时的根源及完美解决方法

《504GatewayTimeout网关超时的根源及完美解决方法》在日常开发和运维过程中,504GatewayTimeout错误是常见的网络问题之一,尤其是在使用反向代理(如Nginx)或... 目录引言为什么会出现 504 错误?1. 探索 504 Gateway Timeout 错误的根源 1.1 后端

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推