1. 程式人生 > >Go語言中如何控制併發

Go語言中如何控制併發

下面這個例子併發列印slice中的每個值(可以檢視上一篇介紹的for..range瞭解其他細節)

var wg sync.WaitGroup
var s []int = []int{1, 2, 3, 4, 5, 6}

for _, value := range s {
    wg.Add(1)
    go func(value int) {
        defer func() {
            wg.Done()
        }()
        t.Logf("go routine value %d", value)
    }(value)

}
wg.Wait()

但有時因為資料庫IO或者其他原因,不可能無限制的併發。這裡給併發設定一個上限。

var wg sync.WaitGroup
var s []int = []int{1, 2, 3, 4, 5, 6}

var pipe = make(chan struct{}, 2)
for _, value := range s {
    wg.Add(1)
    go func(value int) {
        defer func() {
            wg.Done()
            <-pipe
        }()
        pipe <- struct
{}{} t.Logf("go routine value %d", value) }(value) } wg.Wait()

如上述程式碼,我們通過一個帶緩衝的channel來控制go的併發,首先我們聲明瞭一個pipe的channel,來控制程式最多可以併發兩個goroutine

var pipe = make(chan struct{}, 2)

之後再每個goroutine函式中做如下處理,充分利用channel阻塞的特性

  1. 在函式開始時,嘗試寫入該channel中一個值。如果寫入成功,表示當前可以執行該併發,否則阻塞等待。
  2. 當函式結束時從該channel中讀取一個值。
defer func() {
    <-pipe
}()
pipe <- struct{}{}

如何檢視當前程式是否真正只有2個併發,現在確實我還沒有了解到可以檢視的方法。不過,我們可以使用panic語句來簡單檢視一下。

panic執行的時候程式預設會打印出當前程式的所有呼叫棧資訊。我們做一下調整,主動讓程式panic

var wg sync.WaitGroup
var s []int = []int{1, 2, 3, 4, 5, 6}

var pipe = make(chan struct{}, 2)
for _, value := range s {
    wg.Add(1)
    go func(value int) {
        defer func() {
            wg.Done()
            <-pipe
            panic("for check")
        }()
        pipe <- struct{}{}
        t.Logf("go routine value %d", value)
    }(value)

}
wg.Wait()

輸出的結果如下:

panic: for check

goroutine 15 [running]:
speed-push/tests.TestForRange.func1.1(0xc0420f2e60, 0xc0420fe660)
    E:/go-source/kidsguard/src/speed-push/tests/blog_test.go:19 +0xa0
speed-push/tests.TestForRange.func1(0xc0420f2e60, 0xc0420fe660, 0xc042041450, 0x6)
    E:/go-source/kidsguard/src/speed-push/tests/blog_test.go:23 +0x10c
created by speed-push/tests.TestForRange
    E:/go-source/kidsguard/src/speed-push/tests/blog_test.go:23 +0x118
panic: for check

goroutine 10 [running]:
speed-push/tests.TestForRange.func1.1(0xc0420f2e60, 0xc0420fe660)
    E:/go-source/kidsguard/src/speed-push/tests/blog_test.go:19 +0xa0
speed-push/tests.TestForRange.func1(0xc0420f2e60, 0xc0420fe660, 0xc042041450, 0x1)
    E:/go-source/kidsguard/src/speed-push/tests/blog_test.go:23 +0x10c
created by speed-push/tests.TestForRange
    E:/go-source/kidsguard/src/speed-push/tests/blog_test.go:23 +0x118
exit status 2