Go语言协程使用

主协程执行打印,子协程不打印

package main
import ("fmt"
)func do(i int) {fmt.Println("执行中")
}
func main() {fmt.Println("main协程")go do(1)fmt.Println("执行完了")
}//main协程
//执行完了

子协程没有打印输出
原因:主和子协程各执行各的,当主协程执行完go语句就退出,并不会等待子协程执行完成

解决办法三个:

sync. WaitGroup的三个方法 Add(), Done(), Wait()

package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)
}
func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer wg.Done()do(i)}(1)wg.Wait()fmt.Println("执行完了")
}//main协程
//do执行中 1
//执行完了

channel来控制协程

package mainimport ("fmt"
)func do(i int) {fmt.Println("do执行中", i)
}func main() {ch := make(chan bool, 1)fmt.Println("main协程")go func(i int, chp chan<- bool) {defer close(chp)A(i)fmt.Println("do执行完")chp <- true}(1, ch)fmt.Println("wait")<-chfmt.Println("main执行完了")
}//main协程
//wait
//do执行中 1
//do执行完
//main执行完了

通过sync. Cond来实现

package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)
}func main() {var locker = new(sync.Mutex)var cond = sync.NewCond(locker)var done bool = falsefmt.Println("main")cond.L.Lock()go func(i int) {do(i)fmt.Println("do完成")done = truecond.Signal()}(1)fmt.Println("wait")if !done {cond.Wait()cond.L.Unlock()}fmt.Println("main完成")
}//main
//do执行中
//do完成
//main完成

会出现的问题:协程崩溃,主协程也会停止
go可以通过recover来捕获panic,类似try catch的作用

注意

  • recover如果想起作用的话, 必须在defered函数前声明,因为只要panic,后面的函数不会被执行
  • recover函数只有在方法内部发生panic时,返回值才不会为nil,没有panic的情况下返回值为nil
package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)panic("崩溃")defer func() { //在panic后声明defer,不能捕获异常if err := recover(); err != nil {fmt.Println("恢复", err)}}()
}func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer wg.Done()A(i)}(1)wg.Wait()fmt.Println("main执行完了")
}main协程
do执行中 1
main执行完了
panic: 崩溃//goroutine 6 [running]:
//main.do(0x0?)
//        /Volumes/disk/site/go/demo/gfqa/main.go:11 +0x88
//main.main.func1(0x0?)
//        /Volumes/disk/site/go/demo/gfqa/main.go:28 +0x4c
//created by main.main
//        /Volumes/disk/site/go/demo/gfqa/main.go:26 +0x100//进程 已完成,退出代码为 2

改进:panic前声明recover

package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)defer func() { //在panic后声明defer,不能捕获异常if err := recover(); err != nil {fmt.Println("恢复", err)}}()panic("崩溃")
}func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer wg.Done()A(i)}(1)wg.Wait()fmt.Println("main执行完了")
}//do执行中 1
//恢复 崩溃
//main执行完了

其他写法

func do(i int) {fmt.Println("do执行中", i)panic("崩溃")
}func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer func() {if err := recover(); err != nil {fmt.Println("恢复", err)}wg.Done()}()do(i)}(1)wg.Wait()fmt.Println("main执行完了")
}

总结:如果在协程内执行其它函数时,为了保证不崩溃,安全的做法是,提前声明defer recover函数

协程超时控制

用select + channel来进行超时控制
超时 : ctx. Done()或者time. After()或者time. Ticket()
select捕获到其中一个channel有数据,就执行对应的代码,然后退出

注意:channel要用有缓冲的,不然,在超时分支退出时,协程还在卡住,造成goroutine泄露

func do(ctx context.Context, wg *sync.WaitGroup) {ctx, cancle := context.WithTimeout(ctx, time.Second*2)defer func() {cancle()wg.Done()}()done := make(chan struct{}, 1) //执行成功的channelgo func(ctx context.Context) {fmt.Println("go goroutine")time.Sleep(time.Second * 10)done <- struct{}{} //发送完成的信号}(ctx)select {case <-ctx.Done(): //超时fmt.Printf("timeout,err:%v\n", ctx.Err())case <-time.After(3 * time.Second): //超时fmt.Printf("after 1 sec.")case <-done: //程序正常结束fmt.Println("done")}}func main() {fmt.Println("main协程")ctx := context.Background()var wg sync.WaitGroupwg.Add(1)do(ctx, &wg)wg.Wait()fmt.Println("main执行完成")
}
//main协程
//go goroutine
//timeout,err:context deadline exceeded
//main执行完成

总结:runtime. GOMAXPROCS()可以控制当前程序运行时占用的系统核心数,
一个协程不对应一个os线程,是一个m:n的对应关系,协程对应的os线程runtime. GOMAXPROCS默认为系统逻辑cpu数量

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

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

相关文章

椋鸟C语言笔记#36:从源代码到运行

萌新的学习笔记&#xff0c;写错了恳请斧正。 目录 从源代码到运行 翻译环境 编译 预处理 编译 汇编 链接 运行环境 从源代码到运行 在ANSI C的标准中&#xff0c;源代码先经过翻译环境生成可执行程序&#xff0c;再于运行环境中执行 翻译环境 翻译环境由编译与链接…

【C++】unordered_map,unordered_set模拟实现

unordered_map&#xff0c;unordered_set模拟实现 插入普通迭代器const迭代器unordered_map的[ ]接口实现查找修改哈希桶完整代码unordered_map完整代码unordered_set完整代码 喜欢的点赞&#xff0c;收藏&#xff0c;关注一下把&#xff01; 上一篇文章我们把unordered_map和u…

爬虫之Cookie获取:利用浏览器模拟一个cookie出来、面对反爬虫、加密的cookie的应对方法

爬虫之Cookie获取&#xff1a;利用浏览器模拟一个cookie出来、面对反爬虫、加密的cookie的应对方法 在爬虫或模拟请求时&#xff0c;特别是获取验证码的时候&#xff0c;反爬虫的网站的cookie或定期失效&#xff0c;复制出来使用是不行的为了应对这种方式&#xff0c;我们可能…

第十一站:多态练习ODU

实现动态切换 ODU.h #pragma once #include <iostream> using namespace std; #define ODU_TYPE_311_FLAG "311" #define ODU_TYPE_335_FLAG "335" enum class ODU_TYPE {ODU_TYPE_311,ODU_TYPE_335,ODU_TYPE_UNKNOW };class ODU{ public:ODU();//发…

Windows下载安装vcpkg并使用它来安装第三方库(visualstudio)

1.使用Git下载vcpkg仓库&#xff08;下载比较慢&#xff0c;个人比较喜欢打开下面网址然后用迅雷下载&#xff0c;速度飞快&#xff09; git clone "https://github.com/Microsoft/vcpkg.git"2.下载好之后解压打开文件夹&#xff0c;双击bootstrap-vcpkg.bat文件&…

中小企业如何快速融资-----股权融资的四种方式(上)

’在企业融资的多种手段中&#xff0c;股权质押融资、股权交易增值融资、股权增资扩股融资和股权的私募融资&#xff0c;逐渐成为中小企业利用股权实现融资的有效方式。随着市场体系和监管制度的完善&#xff0c;产权市场为投融资者搭建的交易平台日益成熟&#xff0c;越来越多…

ChatGPT 到 Word:使用 Writage 进行复制粘贴魔法

ChatGPT 到 Word&#xff1a;使用 Writage 进行复制粘贴魔法 写在前面Writage的使用 写在前面 随着ChatGPT的日益普及&#xff0c;越来越多的人每天依赖它来完成各种任务。无论是寻找信息、语言翻译、解决数学问题&#xff0c;还是精炼复杂的概念和文本&#xff0c;ChatGPT 都…

React里面table组件的时间轴的位置计算

如上图的时间轴位置计算 计算时间轴位置倒是容易&#xff0c;主要是React里面的antd的table组件怎么监听滚动是个问题 /*** &#xff08;月台/时间&#xff09;为150&#xff0c;时间为100&#xff0c;每个格子为120&#xff0c;120px/30分钟4px/分钟* 00:00分为250px* 00:…

muduo 网络库源码解析和使用

1. base 模块 1.1 API 1.1.1 eventfd int eventfd(unsigned int initval, int flags);&#xff08;1&#xff09;类似信号量&#xff1b;其内部保存了一个 uint64_t 计数器 count&#xff0c;使用 initval 初始化&#xff1b; &#xff08;2&#xff09;read 没有设置 EFD…

Webpack5入门到原理24:优化代码运行性能

优化代码运行性能 Code Split 为什么 打包代码时会将所有 js 文件打包到一个文件中&#xff0c;体积太大了。我们如果只要渲染首页&#xff0c;就应该只加载首页的 js 文件&#xff0c;其他文件不应该加载。 所以我们需要将打包生成的文件进行代码分割&#xff0c;生成多个…

Suricata-7.0 源码分析之流表建立FlowWorker

一、什么是Flow&#xff1f; 二、Flow是怎么建立的&#xff1f; 三、Flow建立的具体过程是什么&#xff1f; 一、什么是Flow&#xff1f;   在Suricata 7.0中&#xff0c;流Flow是指所有相同五元组&#xff08;协议&#xff0c;源IP&#xff0c;目的IP&#xff0c;源端口&am…

makefile里面的变量使用,系统变量

文章目录 makefile里面的变量使用 makefile里面的变量使用 calc:add.o sub.o multi.ogcc add.o sub.o multi.o calc.cpp -o calcadd.o:add.cppgcc -c add.cpp -o add.osub.o:sub.cppgcc -c sub.cpp -o sub.omulti.o:multi.cppgcc -c multi.cpp -o multi.oclean:rm -rf *.o cal…

Linux第32步_编译ST公司的TF-A源码

正点原子STM32MP157开发板使用的CPU型号是STM32MP157DAA1&#xff0c;而开发板硬件参考了ST公司的STM32MP157 EVK开发板&#xff0c;因此我们在移植的时候需要关注“stm32mp157d-ev1”。 一、了解SDK 包 ST公司会从ARM官方下载TF-A软件包&#xff0c;然后将STM32MP1 芯片添加…

算法总结——单调栈

纵有疾风起&#xff0c;人生不言弃。本文篇幅较长&#xff0c;如有错误请不吝赐教&#xff0c;感谢支持。 文章目录 一、单调栈的定义二、单调栈的应用&#xff1a;寻找左边第一个比它小的数单调栈的思想&#xff08;重点&#xff09;&#xff1a;寻找左边第一个比它小的数的下…

Unity常用的优化技巧集锦

Unity性能优化是面试的时候经常被问道的一些内容&#xff0c;今天给大家分享一些常用的Unity的优化技巧和思路&#xff0c;方便大家遇到问题时候参考与学习。 对啦&#xff01;这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白&#xff0c;也有一些正在从事游…

黑杰克详细注释

21点又名黑杰克(Blackjack),起源于法国,已流传到世界各地,有着悠久的历史。现在在世界各地的赌场中都可以看到二十一点。随着互联网的发展,二十一点开始走向网络时代。该游戏由2到6个人玩,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量…

(C语言)编译和链接

前言͟͟͞͞&#x1f48c;&#xff1a;对于现在的各种编译器而言许多都是好多个功能的集成&#xff0c;那么我们的代码到底是如何去实现的呢&#xff1f;难道我们的计算机可以直接读懂我们所写的代码&#xff0c;并运行吗&#xff1f;对于很多细心的小伙伴们可能会想这样的问题…

已解决java.net.BindException异常的正确解决方法,亲测有效!!!

已解决java.net.BindException异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 文章目录 问题分析 报错原因 解决思路 解决方法 检查端口占用 停止占用端口的进程 改变应用程序的端口 允许端口复用 总结 在软件开发中&#xff0c;尤其是…

Hive管理UDF详解

大数据集群下,共有三种管理Hive UDF的方式,如下: 名称重启Hive服务Jar保存目录场景直接JAR配置需要HDFS开发辅助JARs目录配置需要本地目录防止意外覆盖文件可重载辅助JAR配置不需要本地目录频繁更新UDF场景{HIVE_HOME}/auxlib目录需要本地目录不建议{HIVE_HOME}/lib目录需要…

Spring Security 优化鉴权注解:自定义鉴权注解的崭新征程

文章目录 1. 引言2. Spring Security基础2.1 Spring Security概述2.2 PreAuthorize注解 3. 自定义鉴权注解的优势3.1 业务语义更明确3.2 参数化鉴权更灵活3.3 可维护性更好 4. 实现自定义鉴权注解4.1 创建自定义注解4.2 实现鉴权逻辑4.3 注册自定义注解和逻辑4.4 使用自定义注解…