Golang并發模型:合理退出并發協程

goroutine作為Golang并發的核心,我們不僅要關注它們的創建和管理,當然還要關注如何合理的退出這些協程,不(合理)退出不然可能會造成阻塞、panic、程序行為異常、數據結果不正確等問題。這篇文章介紹,如何合理的退出goroutine,減少軟件bug。

goroutine在退出方面,不像線程和進程,不能通過某種手段強制關閉它們,只能等待goroutine主動退出。但也無需為退出、關閉goroutine而煩惱,下面就介紹3種優雅退出goroutine的方法,只要采用這種最佳實踐去設計,基本上就可以確保goroutine退出上不會有問題,盡情享用。

1:使用for-range退出

for-range是使用頻率很高的結構,常用它來遍歷數據,range能夠感知channel的關閉,當channel被發送數據的協程關閉時,range就會結束,接著退出for循環。

它在并發中的使用場景是:當協程只從1個channel讀取數據,然后進行處理,處理后協程退出。下面這個示例程序,當in通道被關閉時,協程可自動退出。

go func(in <-chan int) {// Using for-range to exit goroutine// range has the ability to detect the close/end of a channelfor x := range in {fmt.Printf("Process %d\n", x)}
}(inCh)

2:使用,ok退出

for-select也是使用頻率很高的結構,select提供了多路復用的能力,所以for-select可以讓函數具有持續多路處理多個channel的能力。但select沒有感知channel的關閉,這引出了2個問題

  1. 繼續在關閉的通道上讀,會讀到通道傳輸數據類型的零值,如果是指針類型,讀到nil,繼續處理還會產生nil。
  2. 繼續在關閉的通道上寫,將會panic。

問題2可以這樣解決,通道只由發送方關閉,接收方不可關閉,即某個寫通道只由使用該select的協程關閉,select中就不存在繼續在關閉的通道上寫數據的問題。

問題1可以使用,ok來檢測通道的關閉,使用情況有2種。

第一種:如果某個通道關閉后,需要退出協程,直接return即可。示例代碼中,該協程需要從in通道讀數據,還需要定時打印已經處理的數量,有2件事要做,所有不能使用for-range,需要使用for-select,當in關閉時,ok=false,我們直接返回。

go func() {// in for-select using ok to exit goroutinefor {select {case x, ok := <-in:if !ok {return}fmt.Printf("Process %d\n", x)processedCnt++case <-t.C:fmt.Printf("Working, processedCnt = %d\n", processedCnt)}}
}()

第二種:如果某個通道關閉了,不再處理該通道,而是繼續處理其他case,退出是等待所有的可讀通道關閉。我們需要使用select的一個特征:select不會在nil的通道上進行等待。這種情況,把只讀通道設置為nil即可解決。

go func() {// in for-select using ok to exit goroutinefor {select {case x, ok := <-in1:if !ok {in1 = nil}// Processcase y, ok := <-in2:if !ok {in2 = nil}// Processcase <-t.C:fmt.Printf("Working, processedCnt = %d\n", processedCnt)}// If both in channel are closed, goroutine exitif in1 == nil && in2 == nil {return}}
}()

3:使用退出通道退出

使用,ok來退出使用for-select協程,解決是當讀入數據的通道關閉時,沒數據讀時程序的正常結束。想想下面這2種場景,,ok還能適用嗎?

  1. 接收的協程要退出了,如果它直接退出,不告知發送協程,發送協程將阻塞。
  2. 啟動了一個工作協程處理數據,如何通知它退出?

使用一個專門的通道,發送退出的信號,可以解決這類問題。以第2個場景為例,協程入參包含一個停止通道stopCh,當stopCh被關閉,case <-stopCh會執行,直接返回即可。

當我啟動了100個worker時,只要main()執行關閉stopCh,每一個worker都會都到信號,進而關閉。如果main()向stopCh發送100個數據,這種就低效了。

func worker(stopCh <-chan struct{}) {go func() {defer fmt.Println("worker exit")// Using stop channel explicit exitfor {select {case <-stopCh:fmt.Println("Recv stop signal")returncase <-t.C:fmt.Println("Working .")}}}()return
}

最佳實踐回顧

  1. 發送協程主動關閉通道,接收協程不關閉通道。技巧:把接收方的通道入參聲明為只讀,如果接收協程關閉只讀協程,編譯時就會報錯。
  2. 協程處理1個通道,并且是讀時,協程優先使用for-range,因為range可以關閉通道的關閉自動退出協程。
  3. ,ok可以處理多個讀通道關閉,需要關閉當前使用for-select的協程。
  4. 顯式關閉通道stopCh可以處理主動通知協程退出的場景。

完整示例代碼

本文所有代碼都在倉庫,可查看完整示例代碼:https://github.com/Shitaibin/...

并發系列文章推薦

  • Golang并發模型:輕松入門流水線模型
  • Golang并發模型:輕松入門流水線FAN模式
  • Golang并發模型:并發協程的優雅退出
  • Golang并發模型:輕松入門select
  1. 如果這篇文章對你有幫助,請點個贊/喜歡,鼓勵我持續分享,感謝。
  2. 我的文章列表,點此可查看
  3. 如果喜歡本文,隨意轉載,但請保留此原文鏈接。

一起學Golang-分享有料的Go語言技術

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281400.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281400.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281400.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

劍網服務器維護,12月31日服務器例行維護公告

隱元秘鑒新增以下江湖行里使用趣味道具的成就&#xff1a;壓酒喚客嘗&#xff1a;使用壓酒三十次欲解紅燭意&#xff1a;使用燭影三十次閑情吹笛子&#xff1a;使用吹斷三十次引弦中落雀&#xff1a;使用千鳥三十次黃云動風色&#xff1a;使用風色三十次卷抒平生意&#xff1a;…

一款 Windows 軟件快捷助手

WPF 開發的 Windows 軟件快捷助手Windows 軟件快捷助手作者&#xff1a;WPFDevelopersOrg - 驚鏵原文鏈接&#xff1a;https://github.com/WPFDevelopersOrg/SoftwareHelper框架使用.NET40&#xff1b;Visual Studio 2019;項目使用 MIT 開源許可協議&#xff1b;項目使用 MVV…

關于8位AD_DA轉換芯片的采樣率問題

關于使用Keil計算程序執行時間 打開Keil程序&#xff0c;進入“啟動/停止調試”界面。在需要暫停的地方設置斷點&#xff08;在該句程序前雙擊&#xff09;。在程序上方有一行工具欄&#xff1a;此工具欄分別代表復位、運行、停止、步進、步越、步出、運行到光標處等。 點擊運…

CYQ.Data 數據框架 V4.0 開源版本發布(源碼提供下載,秋色園V2.5版本標配框架)

說明的說明&#xff1a; 博客園團隊兩次移此文出首頁&#xff0c;說 這篇文章不屬于知識分享型文章&#xff0c;并且有廣告嫌疑。 本文的確屬于分享型文章&#xff0c;而且分享的知識點比其它文章都多很多&#xff0c;看看網友回復“謝謝分享”就知道是分享型文章了。 所謂廣告…

oracle 分組后取每組第一條數據

數據格式 分組取第一條的效果 sql SELECT * FROM (SELECT ROW_NUMBER() OVER(PARTITION BY x ORDER BY y DESC) rn, test1.* FROM test1) WHERE rn 1 ;

永大服務器進去顯示字母,永大電梯服務器使用說明

永大電梯服務器使用說明2021-05-25一&#xff0e; 目的&#xff1a;用于工務交車前對MPU和XDR板進行調試。二&#xff0e; 對應作業&#xff1a;1-1對MPU電梯調試接線連接&#xff1a;1).對MPUGB2(A2)版電梯調試時(以及A2前版本)&#xff0c;接線情況如下&#xff1a;連接順序連…

樹莓派Zero 2 W(ubuntu-22.04)通過.NET6和libusb操作USB讀寫

有這個想法的初衷喜歡電子和DIY硬件的朋友對稚暉君應該都不陌生&#xff0c;他定期都會分享一些自己做的好玩的硬件&#xff0c;他之前做了一個ElectronBot桌面機器人我就很感興趣&#xff0c;所以就自己也做了一個。起初我只是自己開發了一個叫電子腦殼的上位機軟件&#xff0…

bzoj4589

fwt 原理并不知道 nim游戲石子異或和0后手贏 那么也就是求a[1]^a[2]^...^a[n]0的方案數 這個和bzoj3992一樣可以dp dp[i][j]表示前i個數異或和為j的方案數 dp[0][0] 1 dp[i][j] dp[i - 1][k] * a[p] p ^ k j a[p] 0 / 1 表示有沒有p這個數 這個東西也不能矩陣快速冪 但是我…

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 85

UnicodeDecodeError: ascii codec cant decode byte 0xe5 in position 85;import sys reload(sys) sys.setdefaultencoding(utf8)

JS設計模式五:職責鏈模式

職責鏈模式簡述 職責連是由多個不同的對象組成的&#xff0c;有發送者跟接收者&#xff0c;分別負責信息的發送跟接收&#xff0c;其中&#xff0c;鏈中第一個對象是 職責連是由多個不同的對象組成的&#xff0c;發送者是發送請求的對象&#xff0c;接收者接收請求并且對其進行…

web框架之Django(一)

Python的WEB框架有Django、Tornado、Flask 等多種&#xff0c;Django相較與其他WEB框架其優勢為&#xff1a;大而全&#xff0c;框架本身集成了ORM、模型綁定、模板引擎、緩存、Session等諸多功能。 基本配置 一、創建django程序 終端命令&#xff1a;django-admin startprojec…

寫一個易于維護使用方便性能可靠的Hybrid框架(一)—— 思路構建

寫一個易于維護使用方便性能可靠的Hybrid框架&#xff08;二&#xff09;—— 插件化 寫一個易于維護使用方便性能可靠的Hybrid框架&#xff08;三&#xff09;—— 配置插件 前言 本來上一篇博文寫完&#xff0c;我就告訴自己&#xff0c;這是最后一篇&#xff0c;之后不再總結…

程序員制作出價值5億外賣神器卻不能取消訂單,你知道嗎?

小編今日給大家帶來RACDisopsable&#xff0c;大家可能有部分人對這個會感覺到很陌生&#xff0c;那么我就用一句話來表達就是他可以幫我們取消訂閱。那么又會有人會對這個產生疑問了&#xff0c;我們什么時候需要用到這個取消訂閱了打個實際的例子來說吧&#xff0c;今天我在餓…

Computer

鏈接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2196https://blog.csdn.net/shuangde800/article/details/9732825#include<iostream> #include<cstdio> #include<algorithm> #include<vector> #include<queue> #include<cmath&…

智慧“昆明”在路上 未來充滿精彩

智慧城市是運用物聯網、云計算、大數據、移動互聯網、空間地理信息集成等新一代信息技術&#xff0c;促進城市規劃、建設、管理和服務智慧化的新理念和新模式。近年來&#xff0c;昆明市全面加快智慧城市建設&#xff0c;力爭通過三年的努力&#xff0c;打造區域信息輻射中心的…

《精讀 Mastering ABP Framework》教程發布

精讀《Mastering ABP Framework》學習總結&#xff0c;掌握軟件開發最佳實踐&#xff0c;構建可維護 .NET 解決方案。從 ABP Framework 框架中學習如何構建現代 WEB 應用程序。掌握 ABP Framework 框架ABP Framework 是一個完整的基礎架構&#xff0c;遵循軟件開發最佳實踐&…

C# 委托知識總結

1.什么是委托&#xff0c;為什么要使用委托 我正在埋頭苦寫程序&#xff0c;突然想喝水&#xff0c;但是又不想自己去掉杯水而打斷自己的思路&#xff0c;于是我就想讓女朋友去給我倒水。她去給我倒水&#xff0c;首先我得讓她知道我想讓她干什么&#xff0c;通知她之后我可以繼…

阿里云大學課程學習有獎征文活動現在開始

2019獨角獸企業重金招聘Python工程師標準>>> "學有所獲&#xff0c;分享為美"--阿里云大學課程學習有獎征文活動開始啦~~ 看課程&#xff0c;寫心得&#xff0c;贏千元大獎&#xff0c;還有機會加入阿里云大學技術作者群&#xff01;想試試自己的技術文筆…

配置網絡測試環境的批處理

引言 有次需要測試 50 臺左右的設備&#xff0c;每個都要連上電腦并搭好測試環境。這種事當然用服務器下發配置最方便&#xff0c;但條件不允許哦&#xff0c;只得手工一臺臺設。 寫了個批處理配置腳本&#xff0c;放到 U 盤上&#xff0c;最好再配上 autorun.inf&#xff0c;嘿…

Android 的系統架構

Android 的系統架構和其它操作系統一樣&#xff0c;采用了分層的架構。android 分為四個層&#xff0c;從高層到低層分別是應用程序層、應用程序框架層、系統運行庫層和 linux 核心層。 Android 是以 Linux 為核心的手機操作平臺&#xff0c;作為一款開放式的操作系統&#xf…