網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
高能預(yù)警
本文包含演示部分,請(qǐng)讀者自行copy代碼編譯體驗(yàn)。
參考資料:sync.WaitGroup / signal.Notify / context.CancelFunc
正文
我們有時(shí)會(huì)希望我們的程序保持執(zhí)行,但是有一種情況是:我們的代碼全部塞入go routine時(shí),主函數(shù)會(huì)立刻退出,本文將和大家分享如何讓main函數(shù)優(yōu)雅地保持執(zhí)行。
問(wèn)題演示:
func main() { go func() { for i := 0; i<10000;i ++ { fmt.Println(i) } }() }
此時(shí)我們可以看到,控制臺(tái)幾乎不會(huì)輸出任何內(nèi)容。究其原因,是主函數(shù)在go routine執(zhí)行前就已經(jīng)結(jié)束,也就是說(shuō)go routine不會(huì)阻塞主函數(shù)。
可能有些讀者會(huì)想到,我直接加個(gè)死循環(huán)在下面,讓主函數(shù)不退出不就行啦?博主表示十分贊同,因?yàn)椴┲骶褪遣捎眠@個(gè)方法,導(dǎo)致服務(wù)器跑滿CPU從而不停的告警。
那么解決辦法是:讓死循環(huán)慢一點(diǎn)執(zhí)行,即添加以下內(nèi)容:
for { time.Sleep(time.Second) }
但是在博主的完美主義光環(huán)加持下,還是希望我們的代碼能更加優(yōu)雅,下面將介紹另外三種比較優(yōu)雅的保持main函數(shù)的辦法。
解決辦法演示
操作系統(tǒng)信號(hào)阻塞
先上代碼:
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") }
官網(wǎng)機(jī)翻:signal.Notify()方法使信號(hào)將傳入c。如果沒(méi)有提供信號(hào),所有傳入的信號(hào)將被中繼到c。
- 這里我們創(chuàng)建了一個(gè)os.Signal類型的管道。當(dāng)管道為空的時(shí)候,讀管道操作“<-”會(huì)阻塞住,直到我們向進(jìn)程發(fā)送一個(gè)信號(hào)(例如 Ctrl+C),才會(huì)繼續(xù)執(zhí)行該操作后面的代碼。
上下文操作阻塞
再上代碼:
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") }
官網(wǎng)機(jī)翻:CancelFunc() 通知操作放棄其(當(dāng)前的)工作。CancelFunc() 不會(huì)等待工作停止。
- 這也是一個(gè)十分優(yōu)雅的辦法,我們創(chuàng)建一個(gè)可以終止的上下文——context.WithCancel(),并在go routine執(zhí)行完畢時(shí)調(diào)用其返回的CancelFunc() 方法,即表示該上下文已經(jīng)結(jié)束了。而在這之前,我們會(huì)使用<-ctx.Done()來(lái)一直等待上下文的結(jié)束,也就是說(shuō)main函數(shù)被成功阻塞,并等待go routine執(zhí)行完畢并執(zhí)行了cancel()方法后優(yōu)雅退出。
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") }
官網(wǎng)機(jī)翻:WaitGroup 等待一組 go routine 完成。主 go routine 調(diào)用 Add() 來(lái)設(shè)置要等待的 go routine 的數(shù)量。
- 我們首先創(chuàng)建一個(gè)WaitGroup{}對(duì)象,然后調(diào)用Add()方法,在里面?zhèn)魅胛覀兘酉聛?lái)會(huì)創(chuàng)建的go routine的數(shù)量,每當(dāng)我們執(zhí)行完一個(gè)go routine時(shí),調(diào)用一次Done()方法,使得正執(zhí)行的go routine的數(shù)量減一,當(dāng)減到0時(shí),Wait()方法將不再等待(阻塞),使main函數(shù)繼續(xù)向下執(zhí)行。
小結(jié)
以上就是我們告別for {}或者select {},并優(yōu)雅地阻塞主函數(shù)的三種辦法,也是博主作為新手時(shí)對(duì)Go語(yǔ)言特性的入門級(jí)體驗(yàn)。
總結(jié)
原文鏈接:https://blog.csdn.net/Liing0/article/details/122481451
相關(guān)推薦
- 2022-03-26 C#?WPF數(shù)據(jù)綁定模板化操作的完整步驟_C#教程
- 2023-05-23 Golang拾遺之實(shí)現(xiàn)一個(gè)不可復(fù)制類型詳解_Golang
- 2022-12-09 ReactQuery系列React?Query?實(shí)踐示例詳解_React
- 2021-12-08 Vmware虛擬機(jī)設(shè)置固定IP地址的方法(?圖文教程)_VMware
- 2022-10-13 Python?變量教程之打包和解包參數(shù)_python
- 2023-07-25 BigDecimal詳解
- 2022-12-24 Kubernetes?kubectl中Pod創(chuàng)建流程源碼解析_云和虛擬化
- 2022-08-03 在Oracle表中進(jìn)行關(guān)鍵詞搜索的過(guò)程_oracle
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支