Go 語言并發模式實踐

在 Go 語言并發編程中,合理的并發模式能顯著提升程序的可維護性和性能。本文將深入解析三種典型的并發模式實現,通過具體案例展示如何優雅地管理任務生命周期、資源池和工作 goroutine 池。

一、runner 模式:任務生命周期管理

在定時任務、批處理等場景中,我們需要對任務執行時間進行控制,并在收到中斷信號時安全終止任務。runner 模式通過通道和超時機制實現了這一需求。

1. 核心實現原理

runner 模式的核心在于通過三個通道協同管理任務狀態:

  • interrupt通道接收操作系統中斷信號
  • complete通道報告任務完成狀態
  • timeout通道控制任務執行超時

下面是 runner 包的核心實現:

// Runner 管理任務執行生命周期
type Runner struct {interrupt chan os.Signal    // 接收中斷信號complete  chan error       // 任務完成通知timeout   <-chan time.Time // 超時控制tasks     []func(int)      // 任務列表closed    bool             // 運行狀態
}// New 創建新的Runner實例
func New(d time.Duration) *Runner {return &Runner{interrupt: make(chan os.Signal, 1),complete:  make(chan error),timeout:   time.After(d),}
}// Add 添加任務到Runner
func (r *Runner) Add(tasks ...func(int)) {r.tasks = append(r.tasks, tasks...)
}// Start 啟動任務執行并監視狀態
func (r *Runner) Start() error {// 注冊中斷信號處理signal.Notify(r.interrupt, os.Interrupt)// 啟動任務執行goroutinego func() {r.complete <- r.run()}()// 等待任務完成或超時select {case err := <-r.complete:return errcase <-r.timeout:return errors.New("任務執行超時")}
}// run 按順序執行注冊的任務
func (r *Runner) run() error {for id, task := range r.tasks {// 檢查是否收到中斷信號if r.gotInterrupt() {return errors.New("收到中斷信號")}// 執行任務task(id)}return nil
}// gotInterrupt 檢測中斷信號
func (r *Runner) gotInterrupt() bool {select {case <-r.interrupt:signal.Stop(r.interrupt)return truedefault:return false}
}

2. 應用場景示例

以下是使用 runner 模式實現定時任務的案例,任務將在 3 秒內執行,超時或收到中斷時終止:

func main() {log.Println("開始執行任務...")// 創建3秒超時的Runnerr := runner.New(3 * time.Second)// 添加三個任務r.Add(func(id int) {log.Printf("任務 %d 執行中...", id)time.Sleep(1 * time.Second)},func(id int) {log.Printf("任務 %d 執行中...", id)time.Sleep(2 * time.Second)},func(id int) {log.Printf("任務 %d 執行中...", id)time.Sleep(3 * time.Second)},)// 執行任務并處理結果if err := r.Start(); err != nil {switch err {case errors.New("任務執行超時"):log.Println("任務超時,終止執行")case errors.New("收到中斷信號"):log.Println("收到中斷,終止執行")}}log.Println("任務處理完成")
}

3. 關鍵特性解析

  • 超時控制:通過time.After設置任務整體執行超時時間
  • 中斷處理:利用signal.Notify捕獲系統中斷信號
  • 任務順序執行:按添加順序依次執行任務,適合有依賴關系的場景
  • 優雅退出:無論超時還是中斷,都能確保資源釋放

二、pool 模式:資源池管理

在數據庫連接、文件句柄等資源管理場景中,資源池模式能有效復用資源,避免頻繁創建和銷毀帶來的性能損耗。

1. 資源池核心設計

pool 模式通過有緩沖通道實現資源的獲取與釋放,確保資源復用:

// Pool 管理可復用資源池
type Pool struct {m        sync.Mutex          // 互斥鎖保護資源池resources chan io.Closer     // 資源通道factory  func() (io.Closer, error) // 資源創建工廠closed   bool                // 資源池狀態
}// New 創建新的資源池
func New(fn func() (io.Closer, error), size uint) (*Pool, error) {if size <= 0 {return nil, errors.New("資源池大小不能小于1")}return &Pool{factory:   fn,resources: make(chan io.Closer, size),}, nil
}// Acquire 從資源池獲取資源
func (p *Pool) Acquire() (io.Closer, error) {select {// 有空閑資源時直接獲取case r, ok := <-p.resources:if !ok {return nil, errors.New("資源池已關閉")}return r, nil// 無空閑資源時創建新資源default:return p.factory()}
}// Release 釋放資源回池
func (p *Pool) Release(r io.Closer) {p.m.Lock()defer p.m.Unlock()// 池已關閉時直接關閉資源if p.closed {r.Close()return}// 嘗試將資源放回池,滿時關閉資源select {case p.resources <- r:log.Println("資源放回池")default:log.Println("資源池已滿,關閉資源")r.Close()}
}// Close 關閉資源池并釋放所有資源
func (p *Pool) Close() {p.m.Lock()defer p.m.Unlock()if p.closed {return}p.closed = true// 關閉通道并釋放資源close(p.resources)for r := range p.resources {r.Close()}
}

2. 數據庫連接池應用案例

以下是使用 pool 模式管理數據庫連接的示例,模擬創建和復用數據庫連接:

// dbConnection 模擬數據庫連接
type dbConnection struct {ID int32
}// Close 實現io.Closer接口
func (db *dbConnection) Close() error {log.Printf("關閉連接 %d\n", db.ID)return nil
}var idCounter int32// createConnection 連接創建工廠
func createConnection() (io.Closer, error) {id := atomic.AddInt32(&idCounter, 1)log.Printf("創建新連接 %d\n", id)return &dbConnection{ID: id}, nil
}func main() {// 創建包含2個連接的資源池p, err := pool.New(createConnection, 2)if err != nil {log.Fatal(err)}defer p.Close()var wg sync.WaitGroupwg.Add(5) // 5個任務競爭2個連接// 模擬5個任務獲取連接for i := 0; i < 5; i++ {go func(taskID int) {defer wg.Done()// 獲取連接conn, err := p.Acquire()if err != nil {log.Fatal(err)}defer p.Release(conn)// 模擬數據庫操作log.Printf("任務 %d 使用連接 %d\n", taskID, conn.(*dbConnection).ID)time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)}(i)}wg.Wait()log.Println("所有任務完成")
}

3. 資源池設計要點

  • 接口抽象:通過io.Closer接口實現資源統一管理
  • 動態擴容:無空閑資源時自動創建新資源
  • 安全釋放:通過互斥鎖保證并發安全
  • 優雅關閉:關閉時釋放所有資源,避免泄漏

三、work 模式:goroutine 池實現

在需要控制并發量的場景中,work 模式通過固定數量的 goroutine 池處理任務,避免創建過多 goroutine 導致資源耗盡。

1. 工作池核心實現

work 模式通過無緩沖通道實現任務與工作 goroutine 的同步:

// Worker 定義工作接口
type Worker interface {Task()
}// Pool 工作goroutine池
type Pool struct {work chan Worker  // 任務通道wg   sync.WaitGroup // 等待組
}// New 創建新的工作池
func New(maxGoroutines int) *Pool {p := Pool{work: make(chan Worker),}p.wg.Add(maxGoroutines)for i := 0; i < maxGoroutines; i++ {go func() {// 從通道獲取任務并執行for w := range p.work {w.Task()}p.wg.Done()}()}return &p
}// Run 提交任務到工作池
func (p *Pool) Run(w Worker) {p.work <- w
}// Shutdown 關閉工作池
func (p *Pool) Shutdown() {close(p.work)p.wg.Wait()
}

2. 任務處理應用案例

以下是使用 work 模式處理批量任務的示例,限制同時運行 3 個 goroutine:

// task 實現Worker接口
type task struct {id int
}func (t task) Task() {log.Printf("任務 %d 開始處理\n", t.id)// 模擬任務處理時間time.Sleep(time.Duration(rand.Intn(2000)) * time.Millisecond)log.Printf("任務 %d 處理完成\n", t.id)
}func main() {// 創建包含3個工作goroutine的池p := work.New(3)defer p.Shutdown()var wg sync.WaitGroupwg.Add(10) // 10個任務// 提交10個任務for i := 0; i < 10; i++ {go func(id int) {defer wg.Done()p.Run(task{id: id})}(i)}wg.Wait()log.Println("所有任務處理完畢")
}

3. 工作池特性分析

  • 固定并發量:通過控制 goroutine 數量避免系統負載過高
  • 任務同步:無緩沖通道保證任務與工作 goroutine 一一對應
  • 簡潔易用:通過接口抽象任務邏輯,解耦業務與并發控制
  • 優雅退出:Shutdown 方法確保所有任務完成后退出

四、三種模式的應用場景對比

模式核心特性適用場景典型案例
runner任務超時控制與中斷處理定時任務、批處理作業數據備份、定時報表生成
pool資源復用與管理數據庫連接、文件句柄等資源管理高并發 Web 服務連接池
work固定并發量任務處理批量任務處理、限制并發請求圖片處理、日志分析

五、并發模式最佳實踐

  1. 根據場景選擇模式

    • 需要超時控制時優先使用 runner 模式
    • 資源復用場景選擇 pool 模式
    • 限制并發量場景使用 work 模式
  2. 接口抽象原則
    通過接口解耦業務邏輯與并發控制,如 runner 的任務函數、pool 的資源接口、work 的 Task 方法

  3. 資源釋放策略
    所有模式都應實現優雅關閉機制,確保資源正確釋放,避免泄漏

  4. 監控與調優
    在生產環境中添加監控指標,根據負載調整參數,如 pool 的大小、work 的 goroutine 數量

Go 語言的并發模式通過簡潔的設計解決了復雜的并發控制問題,合理應用這些模式能讓代碼更清晰、更健壯,同時提升系統的性能和穩定性。在實際開發中,可根據具體需求組合或擴展這些模式,打造更適合業務場景的并發解決方案。

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

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

相關文章

【Java 開發日記】你會不會使用 SpringBoot 整合 Flowable 快速實現工作流呢?

目錄 1、流程引擎介紹 2、創建項目 3、畫流程圖 4、開發接口 4.1 Java 類梳理 ProcessDefinition ProcessInstance Activity Execution Task 4.2 查看流程圖 4.3 開啟一個流程 4.4 將請求提交給組長 4.5 組長審批 4.6 經理審批 4.7 拒絕流程 1、流程引擎介紹 …

面試150 分發糖果

思路 聯想貪心算法&#xff0c;遍歷兩次數組&#xff0c;一次是從左到右遍歷&#xff0c;只比較右邊孩子評分比左邊打的情況。第二次從右到左遍歷&#xff0c;只比較左邊孩子評分比右邊大的情況。最后求和即可 class Solution:def candy(self, ratings: List[int]) -> int…

csp基礎之進制轉換器

一、進制轉換要明白的基礎知識。。。 1、什么是進制&#xff1f; 進制也就是進位計數制&#xff0c;是人為定義的帶進位的計數方法。對于任何一種進制 X 進制&#xff0c;就表示每一位置上的數運算時都是逢 X 進一位。十進制是逢十進一&#xff0c;十六進制是逢十六進一&#…

Zephyr OS藍牙廣播(Advertising)功能實現

目錄 概述 1 Advertising功能介紹 1.1 實現原理 1.2 廣播類型 1.3 廣播數據格式 1.4 優化建議 1.5 常見問題和解決方法 2 Nordic 藍牙廣播&#xff08;Advertising&#xff09;功能實現 2.1 環境準備與SDK基礎 2.2 廣播功能實現 2.3 廣播優化與最佳實踐 3 實際應用案例…

服務器不支持PUT,DELETE 的解決方案

nginx 的更改&#xff1a; set $method $request_method; if ($http_X_HTTP_Method_Override ~* PUT|DELETE) { set $method $http_X_HTTP_Method_Override; } proxy_method $method; axios 的更改&#xff1a; const method config.me…

從0開始學習計算機視覺--Day04--線性分類

從宏觀來看&#xff0c;卷積網絡可以看做是由一個個不同的神經網絡組件組合而成&#xff0c;就像積木一樣通過不同類型的組件搭建形成&#xff0c;其中線性分類器是一個很重要的組件&#xff0c;在很多卷積網絡中都有用到&#xff0c;所以了解清楚它的工作原理對我們后續的學習…

基于ComfyUI與Wan2.1模型的本地化視頻生成環境搭建指南

文章目錄 前言1.軟件準備1.1 ComfyUI1.2 文本編碼器1.3 VAE1.4 視頻生成模型2.整合配置3. 本地運行測試4. 公網使用Wan2.1模型生成視頻4.1 創建遠程連接公網地址5. 固定遠程訪問公網地址總結前言 各位小伙伴們,今天我們將為您展示一套創新的人工智能應用方案!本次教程將指導…

Vue 2 項目中內嵌 md 文件

推薦方案&#xff1a;raw-loader marked 解析 Markdown 第一步&#xff1a;安裝依賴 npm install marked --save npm install raw-loader --save-dev第二步&#xff1a;配置 webpack 支持 .md 文件 打開 vue.config.js 或 webpack.config.js&#xff0c;添加以下配置&#…

Spring AI初識及簡單使用,快速上手。

Spring AI簡介 在當今這樣一個快速發展的技術時代&#xff0c;人工智能&#xff08;AI&#xff09;已經成為各行各業的一種標配。而作為一款主流的Java應用開發框架Spring&#xff0c;肯定會緊跟時代的潮流&#xff0c;所以&#xff0c;推出了Spring AI框架。 官網描述&#…

Flask中的render_template與make_response:生動解析與深度對比

文章目錄 Flask中的render_template與make_response&#xff1a;生動解析與深度對比一、&#x1f31f; 核心概念速覽二、&#xfffd; render_template - 網頁內容的主廚特點與內部機制適用場景高級用法示例 三、&#x1f381; make_response - 響應的包裝專家核心功能解析適用…

WordPress目錄說明

在WordPress建站過程中&#xff0c;理解服務器目錄結構是非常重要的。以下是一個基礎的WordPress服務器目錄指南&#xff1a; /wp-admin/ &#xff1a;這個目錄包含了WordPress網站的所有管理功能&#xff0c;包括用于處理網站后臺的所有PHP文件。 /wp-includes/ &#xff1a;…

HTTP面試題——緩存技術

目錄 HTTP緩存技術有哪些&#xff1f; 什么是強制緩存&#xff1f; 什么是協商緩存&#xff1f; HTTP緩存技術有哪些&#xff1f; 對于一些具有重復性的HTTP請求&#xff0c;比如每次請求得到的數據都是一樣的&#xff0c;我們可以把這對 請求-響應的數據都緩存在本地&#x…

virtual box 不能分配 USB設備 IFX DAS JDS TriBoard TC2X5 V2.0 [0700] 到虛擬電腦 win10

VirtualBox: Failed to attach the USB device to the virtual machine – Bytefreaks.net ISSUE&#xff1a; virtual box 不能分配 USB設備 IFX DAS JDS TriBoard TC2X5 V2.0 [0700] 到虛擬電腦 win10. USB device IFX DAS JDS TriBoard TC2X5 V2.0 with UUID {91680aeb-e1…

Deepoc大模型重構核工業智能基座:混合增強架構與安全增強決策技術?

面向復雜系統的高可靠AI賦能體系構建 Deepoc大模型通過多維度技術突破&#xff0c;顯著提升核工業知識處理與決策可靠性。經核能行業驗證&#xff0c;其生成內容可驗證性提升68%&#xff0c;關鍵參數失真率<0.3%&#xff0c;形成覆蓋核能全鏈條的定制化方案&#xff0c;使企…

第12章:冰箱里的CT掃描儀——計算機視覺如何洞穿食材的“生命密碼“

第11章:冰箱里的CT掃描儀——計算機視覺如何成為食材健康的"超級診斷官" “糟了!冰箱里草莓長出了白色絨毛,雞胸肉滲出了可疑的粉紅色液體!” 這揭示了廚房生存的更基本挑戰:如何像經驗豐富的主廚一樣,一眼洞穿食材的健康密碼? 本章將揭示計算機視覺技術如何賦…

虛幻基礎:窗口——重定向

能幫到你的話&#xff0c;就給個贊吧 &#x1f618; 文章目錄 重定向&#xff1a;給骨架添加兼容骨架。使得不同模型間復用動畫資源 重定向&#xff1a;給骨架添加兼容骨架。使得不同模型間復用動畫資源

CSS 逐幀動畫

CSS 逐幀動畫實現指南 逐幀動畫(frame-by-frame animation)是一種通過快速連續顯示一系列靜態圖像來創造運動效果的技術。以下是使用CSS實現逐幀動畫的幾種方法。 1. 使用 steps() 計時函數 這是實現逐幀動畫最常用的方法&#xff0c;通過animation-timing-function的steps(…

高版本IDEA如何開發低版本jdk項目

問題描述 我這個人比較喜歡新的東西&#xff0c;比如使用idea的時候&#xff0c;我就喜歡最新版本。 但是有個問題&#xff0c;最新版本的idea好像不支持jdk1.6&#xff0c;導致我無法去用新版本idea開發項目。 直到有一天&#xff0c;idea給了我一個提示如下&#xff0c;之…

Java設計模式->責任鏈模式的介紹

目錄 1、責任鏈模式概念 1.1、定義介紹 1.2、流程圖 1.3、優缺點 2、實現 3、應用場景 3.1、Springmvc流程 3.2、mybatis的執行流程 3.3、Spring的過濾器和攔截器 3.4、sentinel限流熔斷 3.5、aop的加載和使用 4、舉例 前言 是一種 行為型設計模式&#xff0c;它通…

【Bluedroid】藍牙啟動之 btm_acl_device_down 流程源碼解析

本文詳細分析Android藍牙協議棧在設備故障時的處理流程。當藍牙設備發生硬件故障或系統異常時,協議棧通過btm_acl_device_down觸發多層次的資源清理和狀態重置,包括ACL連接終止、L2CAP通道釋放、SCO連接清理、BLE拓撲更新、設備數據庫重置等關鍵操作,確保系統安全恢復。 一、…