Golang优雅保持main函数不退出的办法
作者:MiKogy_ 发布时间:2023-07-12 21:15:54
高能预警
本文包含演示部分,请读者自行copy代码编译体验。
参考资料:sync.WaitGroup / signal.Notify / context.CancelFunc
我们有时会希望我们的程序保持执行,但是有一种情况是:我们的代码全部塞入go routine时,主函数会立刻退出,本文将和大家分享如何让main函数优雅地保持执行。
问题演示:
func main() {
go func() {
for i := 0; i<10000;i ++ {
fmt.Println(i)
}
}()
}
此时我们可以看到,控制台几乎不会输出任何内容。究其原因,是主函数在go routine执行前就已经结束,也就是说go routine不会阻塞主函数。
可能有些读者会想到,我直接加个死循环在下面,让主函数不退出不就行啦?博主表示十分赞同,因为博主就是采用这个方法,导致服务器跑满CPU从而不停的告警。
那么解决办法是:让死循环慢一点执行,即添加以下内容:
for {
time.Sleep(time.Second)
}
但是在博主的完美主义光环加持下,还是希望我们的代码能更加优雅,下面将介绍另外三种比较优雅的保持main函数的办法。
解决办法演示
操作系统信号阻塞
先上代码:
func main() {
c := make(chan os.Signal)
signal.Notify(c)
go func() {
fmt.Println("Go routine running")
time.Sleep(3*time.Second)
fmt.Println("Go routine done")
}()
<-c
fmt.Println("bye")
}
官网机翻:signal.Notify()方法使信号将传入c。如果没有提供信号,所有传入的信号将被中继到c。
这里我们创建了一个os.Signal类型的管道。当管道为空的时候,读管道操作“<-”会阻塞住,直到我们向进程发送一个信号(例如 Ctrl+C),才会继续执行该操作后面的代码。
上下文操作阻塞
再上代码:
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
fmt.Println("Go routine running")
time.Sleep(3 * time.Second)
fmt.Println("Go routine done")
cancel()
}()
<-ctx.Done()
fmt.Println("bye")
}
官网机翻:CancelFunc() 通知操作放弃其(当前的)工作。CancelFunc() 不会等待工作停止。
这也是一个十分优雅的办法,我们创建一个可以终止的上下文——context.WithCancel(),并在go routine执行完毕时调用其返回的CancelFunc() 方法,即表示该上下文已经结束了。而在这之前,我们会使用<-ctx.Done()来一直等待上下文的结束,也就是说main函数被成功阻塞,并等待go routine执行完毕并执行了cancel()方法后优雅退出。
WaitGroup阻塞
然后上代码:
func main() {
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
time.Sleep(3*time.Second)
fmt.Println("3 second passed")
wg.Done()
}()
go func() {
time.Sleep(5*time.Second)
fmt.Println("5 second passed")
wg.Done()
}()
wg.Wait()
fmt.Println("bye")
}
官网机翻:WaitGroup 等待一组 go routine 完成。主 go routine 调用 Add() 来设置要等待的 go routine 的数量。
我们首先创建一个WaitGroup{}对象,然后调用Add()方法,在里面传入我们接下来会创建的go routine的数量,每当我们执行完一个go routine时,调用一次Done()方法,使得正执行的go routine的数量减一,当减到0时,Wait()方法将不再等待(阻塞),使main函数继续向下执行
来源:https://blog.csdn.net/Liing0/article/details/122481451


猜你喜欢
- js判断undefined类型今天使用showModalDialog打开页面,返回值时。当打开的页面点击关闭按钮或直接点浏览器上的关闭则返回
- mysql允许在相同列上创建多个索引,无论是有意还是无意,mysql需要单独维护重复的索引,并且优化器在优化查询的时候也需要逐个地进行考虑,
- 一、前言在近半年的 Python 命令行旅程中,我们依次学习了 argparse 、 docopt 、 click 和 fire 库的特点和
- 目录1、将 PDF 转换为音频文件2、从列表中播放随机音乐3、不再有书签了4、清理下载文件夹前言:大家平时有没有注意到你每天可能会执行许多的
- mysql字段的数据类型支持json格式,可以直接存储json数组和json对象。一、插入json数据的方式有两种1、以普通字符串形式插入,
- python中获取字典的key列表和value列表 # -*- coding: utf-8 -*-# 定义一个字典dic = {'剧
- 什么是形态学要了解腐蚀之前,我们需要了解一个概念:形态学。形态学,又名数学形态学(Mathematical Morphology),是图像处
- 1.写作背景Tensorflow官方在2018年宣布,正式发布支持树莓派版本的Tensorflow,编者开始直接用:pip install
- 1.运行效果如图所示2.实现代码如下<!DOCTYPE html><html><head>
- 假设我们需要从各种网页中提取全文,并且要剥离所有HTML标记。通常,默认解决方案是使用BeautifulSoup软件包中的get_text方
- Update dede_addonsoft SET dxylink=REPLACE(dxylink, '.zip',
- 本文实例讲述了Python使用循环神经网络解决文本分类问题的方法。分享给大家供大家参考,具体如下:1、概念1.1、循环神经网络循环神经网络(
- 学习 Python 使程序员能够专注于解决问题,而不是专注于语法,其丰富的库赋予它完成伟大任务所需的力量。1. IDLE使得在 Python
- theme: channing-cyan网页伪静态将 * 页伪装成静态网页,可以提升网页被搜索引擎检索道德概率表现形式为:网址看着像是一个具
- (一)关于体验约瑟夫.派恩和詹姆士.吉尔摩在《体验经济》一书中提出其观点:所谓“体验”就是企业以商品为道具,以服务为舞台,以顾客为中心,创造
- Promise手写Promise作为面试必考题,Promise的手写也是面试官必问的问题,所以对于Promise我们一定要了解透彻框架(fu
- 环境cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) [root@l
- 你是不是觉得每次新建项目都要写一次# coding:utf-8,感觉特烦人呐!懒(fu)人(li)教程来啦,先看效果图吧中文版如图进入设置然
- 内容: ************* 1安装MYSQL后更改了ROOT的密码后用 net startmysql 启动时我就遇到了这样的问题.使
- 1 什么是服务端渲染 SSRserver side render就是通过后端吐模板,而不是通过前端ajax获取数据,拼接字符串。2 为什么需