Go routine使用方法講解
一、怎么才能讓主goroutine等待其它goroutine
方法一:讓主goroutine "sleep"一段時間
func main() {
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println(i)
}(i)
}
time.Sleep(time.Microsecond * 100)
}
缺點是:睡眠的時間很難把握。
方法二:使用通道,使用chan struct{}類型
func main() {
num := 10
var ch = make(chan struct{}, num)
for i := 0; i < num; i++ {
go func(i int) {
fmt.Println(i)
ch <- struct{}{}
}(i)
}
for i := 0; i < num; i++ {
<-ch
}
}
類型字面量struct{}有些類似空接口類型interface{},它代表了即不包含任何字段也不擁有任何方法的空結(jié)構(gòu)體類型。
struct{}類型值的表示法只有一個,即:struct{}{}。并且它占用的內(nèi)存空間是0字節(jié),確切地說,這個值在整個GO程序中永遠都只會存在一份。
方法三:使用sync.WaitGroup
待補充。
二、怎么讓多個goroutine按照既定的順序運行
package main
import (
"fmt"
"sync/atomic"
"time"
)
func main() {
num := uint32(100)
var count uint32 = 0
trigger := func(i uint32, fn func()) {
for {
if atomic.LoadUint32(&count) == i {
fn()
atomic.AddUint32(&count, 1)
break
}
// 這里加Sleep語句是很有必要的
time.Sleep(time.Microsecond)
}
}
for i := uint32(0); i < num; i++ {
go func(i uint32) {
fn := func() {
fmt.Println(i)
}
trigger(i, fn)
}(i)
}
trigger(num, func() {})
}
這里的trigger函數(shù)實現(xiàn)了一種自旋(spining)。
上面的自旋中添加了time.Sleep(time.Microsecond)語句:
這主要是因為:Go 調(diào)度器在需要的時候只會對正在運行的 goroutine 發(fā)出通知,試圖讓它停下來。但是,它卻不會也不能強行讓一個 goroutine 停下來。
所以,如果一條 for 語句過于簡單的話,比如這里的 for 語句就很簡單(因為里面只有一條 if 語句),那么當(dāng)前的 goroutine 就可能不會去正常響應(yīng)(或者說沒有機會響應(yīng))Go 調(diào)度器的停止通知。
因此,這里加一個 sleep 是為了:在任何情況下(如任何版本的 Go、任何計算平臺下的 Go、任何的 CPU 核心數(shù)等),內(nèi)含這條 for 語句的這些 goroutine 都能夠正常地響應(yīng)停止通知。
不加Sleep語句,可能會導(dǎo)致一直搶占不到資源,也就沒有機會運行,就可能會導(dǎo)致程序一直運行,不會終止。
樂觀鎖:總是假設(shè)在“我”操作共享資源的過程中沒有“其他人”競爭操作。如果發(fā)現(xiàn)“其他人”確實在此期間競爭了,也就是發(fā)現(xiàn)假設(shè)失敗,那就等一等再操作。CAS原子操作基本上能夠體現(xiàn)出這種思想。通常,低頻的并發(fā)操作適合用樂觀鎖。樂觀鎖一般會用比較輕量級的同步方法(如原子操作),但也不是100%。注意,高頻的操作用樂觀鎖的話反而有可能影響性能,因為多了一步“探查是否有人與我競爭”的操作(當(dāng)然了,標(biāo)準(zhǔn)的CAS操作可以把這種影響降到最低)。
悲觀鎖:總是假設(shè)在“我”操作共享資源的過程中一定有“其他人”競爭操作。所以“我”會先用某種同步方法(如互斥鎖)保護我的操作。這樣的話,“我”在將要操作的時候就沒必要去探查是否有人與我競爭(因為“我”總是假設(shè)肯定有競爭,而且已經(jīng)做好了保護)。通常,頻次較高的并發(fā)操作適合用悲觀鎖。不過,如果并發(fā)操作的頻次非常低,用悲觀鎖也是可以的,因為這種情況下對性能影響不大。
最后,一定要注意,使用任何同步方法和異步方法都首先要考慮程序的正確性,并且還要考慮程序的性能。程序的正確性一定要靠功能測試來保障,程序的性能一定要靠性能測試來保障。
到此這篇關(guān)于Go routine使用方法講解的文章就介紹到這了,更多相關(guān)Go routine內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Golang實現(xiàn)Redis協(xié)議解析器
這篇文章主要為大家詳細介紹了如何通過GO語言編寫簡單的Redis協(xié)議解析器,文中的示例代碼講解詳細,對我們深入了解Go語言有一定的幫助,需要的可以參考一下2023-03-03

