Go 并發編程深度指南

Go 并發編程深度指南

Go 語言以其內置的并發原語而聞名,通過 goroutine 和 channel 提供了一種高效、安全的并發編程模型。本文將全面解析 Go 的并發機制及其實際應用。

核心概念:Goroutines 和 Channels

1. Goroutines (協程)

Go 的輕量級線程實現,開銷極小:

func main() {// 啟動一個協程go func() {fmt.Println("Hello from goroutine!")}()// 讓主程序等待一會兒time.Sleep(100 * time.Millisecond)
}

2. Channels (通道)

協程間通信的主要方式:

func main() {// 創建無緩沖通道ch := make(chan string)go func() {time.Sleep(500 * time.Millisecond)ch <- "message"}()// 阻塞等待消息msg := <-chfmt.Println("Received:", msg)
}

并發模式與最佳實踐

1. WaitGroup 控制協程組

func processTasks(tasks []string) {var wg sync.WaitGroupfor i, task := range tasks {wg.Add(1) // 增加計數go func(task string, id int) {defer wg.Done() // 結束時減少計數processTask(task, id)}(task, i)}wg.Wait() // 等待所有完成fmt.Println("All tasks completed")
}

2. Worker Pool 模式

func worker(id int, jobs <-chan int, results chan<- int) {for j := range jobs {fmt.Printf("Worker %d started job %d\n", id, j)time.Sleep(time.Second)fmt.Printf("Worker %d finished job %d\n", id, j)results <- j * 2}
}func main() {jobs := make(chan int, 100)results := make(chan int, 100)// 啟動3個workerfor w := 1; w <= 3; w++ {go worker(w, jobs, results)}// 發送9個任務for j := 1; j <= 9; j++ {jobs <- j}close(jobs)// 接收結果for a := 1; a <= 9; a++ {<-results}
}

3. Select 多路復用

func main() {ch1 := make(chan string)ch2 := make(chan string)go func() {time.Sleep(1 * time.Second)ch1 <- "One"}()go func() {time.Sleep(2 * time.Second)ch2 <- "Two"}()// 同時等待兩個通道for i := 0; i < 2; i++ {select {case msg1 := <-ch1:fmt.Println("Received", msg1)case msg2 := <-ch2:fmt.Println("Received", msg2)}}
}

4. Context 控制協程生命周期

func worker(ctx context.Context) {for {select {case <-ctx.Done():fmt.Println("Worker canceled")returncase <-time.After(500 * time.Millisecond):fmt.Println("Working...")}}
}func main() {ctx, cancel := context.WithCancel(context.Background())go worker(ctx)// 運行3秒后取消time.Sleep(3 * time.Second)cancel()// 給worker時間響應取消time.Sleep(500 * time.Millisecond)
}

5. Mutex 保護共享資源

type SafeCounter struct {mu sync.Mutexv  int
}func (c *SafeCounter) Inc() {c.mu.Lock()defer c.mu.Unlock()c.v++
}func (c *SafeCounter) Value() int {c.mu.Lock()defer c.mu.Unlock()return c.v
}func main() {counter := SafeCounter{}var wg sync.WaitGroupfor i := 0; i < 1000; i++ {wg.Add(1)go func() {defer wg.Done()counter.Inc()}()}wg.Wait()fmt.Println("Final count:", counter.Value())
}

高級并發模式

1. 扇入/扇出 (Fan-in/Fan-out)

// 生產者
func producer(done <-chan struct{}, nums ...int) <-chan int {out := make(chan int)go func() {defer close(out)for _, n := range nums {select {case out <- n:case <-done:return}}}()return out
}// 消費者
func consumer(done <-chan struct{}, in <-chan int, id int) <-chan int {out := make(chan int)go func() {defer close(out)for n := range in {// 模擬處理result := n * nselect {case out <- result:case <-done:return}}}()return out
}// 扇入多個通道
func fanIn(done <-chan struct{}, chs ...<-chan int) <-chan int {var wg sync.WaitGroupout := make(chan int)// 定義輸出函數output := func(c <-chan int) {defer wg.Done()for n := range c {select {case out <- n:case <-done:return}}}wg.Add(len(chs))for _, c := range chs {go output(c)}// 啟動goroutine等待所有完成go func() {wg.Wait()close(out)}()return out
}func main() {done := make(chan struct{})defer close(done)// 創建輸入通道in := producer(done, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)// 啟動3個消費者c1 := consumer(done, in, 1)c2 := consumer(done, in, 2)c3 := consumer(done, in, 3)// 合并結果for result := range fanIn(done, c1, c2, c3) {fmt.Println("Result:", result)}
}

2. Future/Promise 模式

func futureWork(input int) <-chan int {result := make(chan int)go func() {// 模擬耗時操作time.Sleep(500 * time.Millisecond)result <- input * 2close(result)}()return result
}func main() {f1 := futureWork(5)f2 := futureWork(10)// 并行執行后獲取結果r1 := <-f1r2 := <-f2fmt.Println("Results:", r1, r2) // 10, 20
}

性能優化與陷阱規避

1. 限制并發數

func controlledWork(workers int) {sem := make(chan struct{}, workers)var wg sync.WaitGroupfor i := 0; i < 100; i++ {wg.Add(1)go func(id int) {defer wg.Done()sem <- struct{}{}        // 獲取信號量defer func() { <-sem }() // 釋放信號量// 執行工作fmt.Printf("Worker %d starting\n", id)time.Sleep(time.Second)fmt.Printf("Worker %d done\n", id)}(i)}wg.Wait()
}

2. 通道選擇與超時

func fetchData(url string, timeout time.Duration) (string, error) {ch := make(chan string, 1)go func() {// 模擬網絡請求time.Sleep(500 * time.Millisecond)ch <- "Response from " + url}()select {case res := <-ch:return res, nilcase <-time.After(timeout):return "", errors.New("request timed out")}
}

3. 避免競態條件

// 壞: 共享變量無保護
var count int
for i := 0; i < 100; i++ {go func() {count++ // 數據競爭!}()
}// 好: 使用互斥鎖
var (mu    sync.Mutexcount int
)
for i := 0; i < 100; i++ {go func() {mu.Lock()defer mu.Unlock()count++}()
}// 更好: 使用通道通信
ch := make(chan struct{})
go func() {count := 0for range ch {count++}
}()
for i := 0; i < 100; i++ {ch <- struct{}{}
}

并發性能分析工具

  1. ??Race Detector??:

    go run -race yourprogram.go
  2. ??pprof??:

    import _ "net/http/pprof"func main() {go func() {log.Println(http.ListenAndServe("localhost:6060", nil))}()// 程序主體...
    }

    然后使用 go tool pprof http://localhost:6060/debug/pprof/profile 進行分析

  3. ??Benchmark??:

    func BenchmarkWork(b *testing.B) {for i := 0; i < b.N; i++ {doWork()}
    }

Go 并發設計哲學

  1. ??不要通過共享內存來通信,而應通過通信來共享內存??
  2. ??并發不是并行?? - 并發是設計結構,并行是執行方式
  3. ??利用組合而不是繼承?? - 通過組合小的并發原語構建復雜系統
  4. ??錯誤處理也是控制流?? - 將錯誤作為值傳遞,通過通道處理

Go 的并發模型提供了強大而簡單的工具集,使開發者能夠構建高效、可伸縮的并發系統。通過理解 goroutine、channel 和各種同步原語的使用方法,開發者可以避免許多并發編程的常見陷阱,創建出更加穩健的系統。

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

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

相關文章

vue和uniapp聊天頁面右側滾動條自動到底部

1.vue右側滾動條自動到底部 <div ref"newMessage1"></div> <!-- 定義<div ref"newMessage1"></div>與<div v-for”item in list“>循環同級定義-->定義方法 scrollToBottomCenter(){this.$nextTick(() > {this.$re…

iOS 項目怎么構建穩定性保障機制?一次系統性防錯經驗分享(含 KeyMob 工具應用)

崩潰、內存飆升、后臺任務未釋放、頁面卡頓、日志丟失——穩定性問題&#xff0c;不一定會立刻崩&#xff0c;但一旦積累&#xff0c;就是“上線后救不回來的代價”。 穩定性保障不是某個工具的功能&#xff0c;而是一套貫穿開發、測試、上線全流程的“觀測分析防范”機制。 …

JMeter函數整理

"_csvRead"函數 csvRead函數是從外部讀取參數&#xff0c;csvRead函數可以從一個文件中讀取多個參數。 下面具體講一下如何使用csvread函數&#xff1a; 1.新建一個csv或者text文件&#xff0c;里面保存要讀取的參數&#xff0c;每個參數間用逗號相隔。每行表示每一組…

深入理解 React Hooks

在當今的 React 開發中,Hooks 已經成為構建函數組件的核心工具。自 React 16.8 版本引入以來,Hooks 徹底改變了開發者編寫 React 組件的方式,使得狀態管理和副作用處理變得更加簡潔和直觀。本文將全面介紹 React 提供的各種 Hooks,從基礎的 useState 和 useEffect,到高級的…

Doris-2:單虛擬機上非docker化安裝Doris實驗環境

Doris-2:單虛擬機上非docker化安裝Doris實驗環境 1.安裝1.1.環境說明1.2.基礎準備1.2.1.JDK1.2.2.操作系統配置(使用root或者有權賬戶)1.2.2.1.修改環境變量1.2.2.2.修改虛擬內存區域1.2.2.3.關閉swap1.2.2.4.關閉防火墻1.2.2.5.創建用戶和組1.3.安裝doris1.3.1.解壓1.3.2.配置…

C# SqlSugar:依賴注入與倉儲模式實踐

C# SqlSugar&#xff1a;依賴注入與倉儲模式實踐 在 C# 的應用開發中&#xff0c;數據庫操作是必不可少的環節。為了讓數據訪問層更加簡潔、高效且易于維護&#xff0c;許多開發者會選擇成熟的 ORM&#xff08;對象關系映射&#xff09;框架&#xff0c;SqlSugar 就是其中備受…

Razor編程中@Helper的用法大全

文章目錄 第一章&#xff1a;Helper基礎概念1.1 Helper的定義與作用1.2 Helper的基本語法結構1.3 Helper與HtmlHelper的區別 第二章&#xff1a;基礎Helper用法2.1 無參數Helper2.2 帶簡單參數的Helper2.3 帶默認值的參數2.4 使用模型作為參數 第三章&#xff1a;高級Helper用法…

Python-正則表達式(re 模塊)

目錄 一、re 模塊的使用過程二、正則表達式的字符匹配1. 匹配開頭結尾2. 匹配單個字符3. 匹配多個字符4. 匹配分組5. Python 代碼示例 三、re 模塊的函數1. 函數一覽表2. Python 代碼示例1&#xff09;search 與 finditer2&#xff09;findall3&#xff09;sub4&#xff09;spl…

前端知識導圖

前端知識導圖 參考&#xff1a;字節標準 前端知識導圖 通用基礎 1、編程語言 HTML CSS JS TS 2、計算機基礎 計算機網略 數據結構 算法&#xff1a;二分查找、十大排序、二叉樹先中后和層次遍歷、集合交并集、leetcode刷題經驗 編譯構建 webpack & vite 應用基礎 開…

moon游戲服務器-demo運行

下載地址 https://github.com/sniper00/MoonDemo redis安裝 Redis-x64-3.0.504.msi 服務器配置文件 D:\gitee\moon_server_demo\serverconf.lua 貌似不修改也可以的&#xff0c;redis不要設置密碼 windows編譯 安裝VS2022 Community 下載premake5.exe放MoonDemo\server\moon 雙…

Webpack性能優化:構建速度與體積優化策略

一、構建速度優化 1、??升級Webpack和Node.js?? ??優化效果??&#xff1a;Webpack 4比Webpack 3構建時間降低60%-98%。??原因??&#xff1a; V8引擎優化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默認使用更快的md4哈希算法。AST直接從Loa…

ajax學習手冊

Ajax 通俗易懂學習手冊 目錄 Ajax 基礎概念XMLHttpRequest 詳解Fetch API (現代方式)處理不同數據格式錯誤處理和狀態碼Ajax 高級技巧實戰項目案例最佳實踐 Ajax 基礎概念 什么是 Ajax&#xff1f; Ajax Asynchronous JavaScript And XML 通俗解釋&#xff1a; Ajax 就像…

人工智能學習02-安裝環境

人工智能學習概述—快手視頻 人工智能學習02-安裝—快手視頻 Python安裝 Python安裝分為兩種方法&#xff0c;一是從官網(https://www.python.org/)下載Python工具(比如python-2.7.msi)進行安裝&#xff0c;并設置Path環境變量&#xff1b;二是下載工具Anaconda集成環境進行安…

電腦開不了機,主板顯示67碼解決過程

文章目錄 現象分析內存條問題BIOS設置問題其它問題 解決清理內存條金手指所需工具操作步驟注意事項 電腦在運行過程中&#xff0c;顯示內存不足&#xff0c;重啟電腦卻無法啟動。 現象 System Initialization 主板風扇是轉的&#xff0c;也有燈光顯示&#xff0c;插上屏幕&am…

在ubuntu等linux系統上申請https證書

使用 Certbot 自動申請 安裝 Certbot Certbot 是 Let’s Encrypt 官方推薦的自動化工具&#xff0c;支持多種操作系統和服務器環境。 在 Ubuntu/Debian 上&#xff1a; sudo apt update sudo apt install certbot申請證書 純手動方式&#xff08;不自動配置&#xff09;&…

springboot的test模塊使用Autowired注入失敗

springboot的test模塊使用Autowired注入失敗的原因&#xff1a; 注入失敗的原因可能是用了junit4的包的Test注解 import org.junit.Test;解決方法&#xff1a;再加上RunWith(SpringRunner.class)注解即可 或者把Test由junit4改成junit5的注解&#xff0c;就不用加上RunWith&…

Cursor Rules 使用

前言 最近在使用 Cursor 進行編程輔助時&#xff0c;發現 AI 生成的代碼風格和當前的代碼風格大相徑庭。而且有時它會輸出很奇怪的代碼&#xff0c;總是不符合預期。 遂引出本篇&#xff0c;介紹一下 Rules &#xff0c;它就可以做一些規范約束之類的事情。 什么是 Cursor R…

項目任務,修改svip用戶的存儲空間。

修改存儲空間 3GB->5GB&#xff0c;這是項目任務&#xff0c;首先有人任務就要去思考實現思路&#xff0c;首先存儲空間&#xff0c;也就是說不只是前端樣式3GB改一下就可以了&#xff0c;那用戶實際還是3GB&#xff0c;所以我們去網站看后端誰返回給我們了3GB&#xff0c;我…

【無標題】路徑問題的革命性重構:基于二維拓撲收縮色動力學模型的零點隧穿理論

路徑問題的革命性重構&#xff1a;基于二維拓撲收縮色動力學模型的零點隧穿理論 一、傳統路徑模型的根本缺陷 在經典正方形路徑問題中&#xff08;圖1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[無直接路徑] B -…

iview中的table組件點擊一行中的任意一點選中本行

<Table border ref"selection" size"small" on-row-click"onClickRow"></Table>// table組件點擊一行任意位置選中onClickRow(row, index) {this.$refs.selection.toggleSelect(index)}寫上toggleSelect(index)方法即可&#xff0c;…