go 簡潔的并發
多核處理器越來越普及。有沒有一種簡單的辦法,能夠讓我們寫的軟件釋放多核的威力?是有的。隨著Golang, Erlang, Scala等為并發設計的程序語言的興起,新的并發模式逐漸清晰。正如過程式編程和面向對象一樣,一個好的編程模式有一個極其簡潔的內核,還有在此之上豐富的外延。可以解決現實世界中各種各樣的問題。本文以GO語言為例,解釋其中內核、外延。
前言
Java 中有一系列的線程同步的方法,go 里面有 goroutine(協程),先看下下面的代碼執行的結果是什么呢?
package main
import (
"fmt"
)
func main() {
go func() {
fmt.Println("Goroutine 1")
}()
go func() {
fmt.Println("Goroutine 2")
}()
}
執行以上代碼很可能看不到輸出。
因為有可能這兩個協程還沒得到執行,主協程就已經結束了,而主協程結束時會結束所有其他協程,所以導致代碼運行的結果什么都沒有。
估計不少新接觸 go 的童鞋都會對此郁悶😒,可能會問那么該如何等待主協程中創建的協程執行完畢之后再結束主協程呢?
下面說幾種可以解決的方法:
Sleep 一段時間
在 main 方法退出之前 sleep 一段時間就可能會出現結果了,如下代碼:
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秒,等待上面兩個協程結束
}
這兩個簡單的協程執行消耗的時間很短的,所以你會發現現在就有結果出現了。
Goroutine 1
Goroutine 2
為什么上面我要說 “可能會出現” ?
因為 sleep 這個時間目前是設置的 1s,如果我這兩個協程里面執行了很復雜的邏輯操作(時間大于 1s),那么就會發現依舊也是無結果打印出來的。
那么就可以發現這種方式得到問題所在了:我們無法確定需要睡眠多久
上面那種方式有問題,go 里面其實也可以用管道來實現同步的。
管道實現同步
那么用管道怎么實現同步呢?show code:
package main
import (
"fmt"
)
func main() {
ch := make(chan struct{})
count := 2 // count 表示活動的協程個數
go func() {
fmt.Println("Goroutine 1")
ch - struct{}{} // 協程結束,發出信號
}()
go func() {
fmt.Println("Goroutine 2")
ch - struct{}{} // 協程結束,發出信號
}()
for range ch {
// 每次從ch中接收數據,表明一個活動的協程結束
count--
// 當所有活動的協程都結束時,關閉管道
if count == 0 {
close(ch)
}
}
}
這種方式是一種比較完美的解決方案, goroutine / channel 它們也是在 go 里面經常搭配在一起的一對。
sync.WaitGroup
其實 go 里面也提供了更簡單的方式 —— 使用 sync.WaitGroup。
WaitGroup 顧名思義,就是用來等待一組操作完成的。WaitGroup 內部實現了一個計數器,用來記錄未完成的操作個數,它提供了三個方法:
- Add() 用來添加計數
- Done() 用來在操作結束時調用,使計數減一
- Wait() 用來等待所有的操作結束,即計數變為 0,該函數會在計數不為 0 時等待,在計數為 0 時立即返回
繼續 show code:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(2) // 因為有兩個動作,所以增加2個計數
go func() {
fmt.Println("Goroutine 1")
wg.Done() // 操作完成,減少一個計數
}()
go func() {
fmt.Println("Goroutine 2")
wg.Done() // 操作完成,減少一個計數
}()
wg.Wait() // 等待,直到計數為0
}
你會發現也是可以看到運行結果的,是不是發現這種方式是很簡單的。
總結
以上所述是小編給大家介紹的Go 并發實現協程同步的多種解決方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
您可能感興趣的文章:- go等待一組協程結束的操作方式
- golang協程池模擬實現群發郵件功能
- 解決go在函數退出后子協程的退出問題
- Go使用協程交替打印字符
- Golang 之協程的用法講解
- go 協程返回值處理操作
- 淺談golang for 循環中使用協程的問題
- Go并發:使用sync.WaitGroup實現協程同步方式