Go 并發(fā)實現(xiàn)協(xié)程同步的多種解決方法
go 簡潔的并發(fā)
多核處理器越來越普及。有沒有一種簡單的辦法,能夠讓我們寫的軟件釋放多核的威力?是有的。隨著Golang, Erlang, Scala等為并發(fā)設計的程序語言的興起,新的并發(fā)模式逐漸清晰。正如過程式編程和面向對象一樣,一個好的編程模式有一個極其簡潔的內(nèi)核,還有在此之上豐富的外延??梢越鉀Q現(xiàn)實世界中各種各樣的問題。本文以GO語言為例,解釋其中內(nèi)核、外延。
前言
Java 中有一系列的線程同步的方法,go 里面有 goroutine(協(xié)程),先看下下面的代碼執(zhí)行的結果是什么呢?
package main import ( "fmt" ) func main() { go func() { fmt.Println("Goroutine 1") }() go func() { fmt.Println("Goroutine 2") }() }
執(zhí)行以上代碼很可能看不到輸出。
因為有可能這兩個協(xié)程還沒得到執(zhí)行,主協(xié)程就已經(jīng)結束了,而主協(xié)程結束時會結束所有其他協(xié)程,所以導致代碼運行的結果什么都沒有。
估計不少新接觸 go 的童鞋都會對此郁悶😒,可能會問那么該如何等待主協(xié)程中創(chuàng)建的協(xié)程執(zhí)行完畢之后再結束主協(xié)程呢?
下面說幾種可以解決的方法:
Sleep 一段時間
在 main 方法退出之前 sleep 一段時間就可能會出現(xiàn)結果了,如下代碼:
package main import ( "fmt" "time" ) func main() { go func() { fmt.Println("Goroutine 1") }() go func() { fmt.Println("Goroutine 2") }() time.Sleep(time.Second * 1) // 睡眠1秒,等待上面兩個協(xié)程結束 }
這兩個簡單的協(xié)程執(zhí)行消耗的時間很短的,所以你會發(fā)現(xiàn)現(xiàn)在就有結果出現(xiàn)了。
Goroutine 1
Goroutine 2
為什么上面我要說 “可能會出現(xiàn)” ?
因為 sleep 這個時間目前是設置的 1s,如果我這兩個協(xié)程里面執(zhí)行了很復雜的邏輯操作(時間大于 1s),那么就會發(fā)現(xiàn)依舊也是無結果打印出來的。
那么就可以發(fā)現(xiàn)這種方式得到問題所在了:我們無法確定需要睡眠多久
上面那種方式有問題,go 里面其實也可以用管道來實現(xiàn)同步的。
管道實現(xiàn)同步
那么用管道怎么實現(xiàn)同步呢?show code:
package main import ( "fmt" ) func main() { ch := make(chan struct{}) count := 2 // count 表示活動的協(xié)程個數(shù) go func() { fmt.Println("Goroutine 1") ch <- struct{}{} // 協(xié)程結束,發(fā)出信號 }() go func() { fmt.Println("Goroutine 2") ch <- struct{}{} // 協(xié)程結束,發(fā)出信號 }() for range ch { // 每次從ch中接收數(shù)據(jù),表明一個活動的協(xié)程結束 count-- // 當所有活動的協(xié)程都結束時,關閉管道 if count == 0 { close(ch) } } }
這種方式是一種比較完美的解決方案, goroutine / channel 它們也是在 go 里面經(jīng)常搭配在一起的一對。
sync.WaitGroup
其實 go 里面也提供了更簡單的方式 —— 使用 sync.WaitGroup。
WaitGroup 顧名思義,就是用來等待一組操作完成的。WaitGroup 內(nèi)部實現(xiàn)了一個計數(shù)器,用來記錄未完成的操作個數(shù),它提供了三個方法:
- Add() 用來添加計數(shù)
- Done() 用來在操作結束時調用,使計數(shù)減一
- Wait() 用來等待所有的操作結束,即計數(shù)變?yōu)?0,該函數(shù)會在計數(shù)不為 0 時等待,在計數(shù)為 0 時立即返回
繼續(xù) show code:
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(2) // 因為有兩個動作,所以增加2個計數(shù) go func() { fmt.Println("Goroutine 1") wg.Done() // 操作完成,減少一個計數(shù) }() go func() { fmt.Println("Goroutine 2") wg.Done() // 操作完成,減少一個計數(shù) }() wg.Wait() // 等待,直到計數(shù)為0 }
你會發(fā)現(xiàn)也是可以看到運行結果的,是不是發(fā)現(xiàn)這種方式是很簡單的。
總結
以上所述是小編給大家介紹的Go 并發(fā)實現(xiàn)協(xié)程同步的多種解決方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關文章
淺析Go中函數(shù)的健壯性,panic異常處理和defer機制
這篇文章主要為大家詳細介紹了Go中函數(shù)的健壯性,panic異常處理和defer機制的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-10-10golang微服務框架kratos實現(xiàn)Socket.IO服務的方法
本文主要介紹了golang微服務框架kratos實現(xiàn)Socket.IO服務的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-06-06深入理解Go gin框架中Context的Request和Writer對象
這篇文章主要為大家詳細介紹了Go語言的gin框架中Context的Request和Writer對象,文中的示例代碼講解詳細,對我們深入了解Go語言有一定的幫助,快跟隨小編一起學習一下吧2023-04-04Go語言使用Timeout Context取消任務的實現(xiàn)
本文主要介紹了Go語言使用Timeout Context取消任務的實現(xiàn),包括基本的任務取消和控制HTTP客戶端請求的超時,具有一定的參考價值,感興趣的可以了解一下2024-01-01