並列のゴルーチン間でチャネルを共有する方法を教えるためにこのサンプルコードを書いており、競合状態に遭っています。プログラムは、システム上に利用可能なCPUがあるように多くのゴルーチンを起動する必要があります。 blチャネルにアクセスする最初のゴルーチンは、チャネルをfalseにするように設定し、他のゴルーチンがstチャネル上のループにアクセスできないようにします。他のゴルーチンは、blチャネルにアクセスしてstチャネルから読み込み、各値を出力する最初のゴルーチンとして終了する必要があります。私は、コードを実行すると並列ゴルーチン間でチャネルを共有するときのGolang競合状態
package main
import (
"fmt"
"runtime"
"strconv"
"math/rand"
"time"
"sync"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
var wg sync.WaitGroup
st := make(chan string)
bl := make(chan bool)
go func() {bl <- true}()
for i := 0; i < runtime.NumCPU(); i++ {
wg.Add(1)
go func(x int) {
defer wg.Done()
fmt.Println("me: ", strconv.Itoa(x))
can := <- bl
bl <- false
if can {
for val := range st {
t := strconv.Itoa(rand.Int()%3)+"s"
dur, _ := time.ParseDuration(t)
time.Sleep(dur)
fmt.Println("time: ", t," i: ", strconv.Itoa(x), val)
}
}
fmt.Println("done: ", strconv.Itoa(x))
}(i)
}
for i := 0; i < 10; i++ {
st <- "n: "+strconv.Itoa(i)
}
wg.Wait()
close(st)
}
、私は次のエラーを取得する:
$ go run share.go
me: 1
me: 0
me: 2
me: 3
done: 0
done: 2
time: 2s i: 1 n: 0
time: 1s i: 1 n: 1
time: 0s i: 1 n: 2
time: 2s i: 1 n: 3
time: 2s i: 1 n: 4
time: 2s i: 1 n: 5
time: 0s i: 1 n: 6
time: 2s i: 1 n: 7
time: 2s i: 1 n: 8
time: 2s i: 1 n: 9
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc4200701bc)
/usr/local/go/src/runtime/sema.go:47 +0x30
sync.(*WaitGroup).Wait(0xc4200701b0)
/usr/local/go/src/sync/waitgroup.go:131 +0x97
main.main()
/share.go:80 +0x1ef
goroutine 36 [chan receive]:
main.main.func2(0xc4200701b0, 0xc42006e0c0, 0xc42006e060, 0x1)
/share.go:64 +0x23e
created by main.main
/share.go:73 +0x127
goroutine 38 [chan send]:
main.main.func2(0xc4200701b0, 0xc42006e0c0, 0xc42006e060, 0x3)
/share.go:61 +0x1ef
created by main.main
/share.go:73 +0x127
exit status 2
は私がblチャネルのためのこのレースの条件を処理するかどうかはわかりません。最後のgoroutineはblチャンネルからの読み込みを試みているようですが、それ以前のgoroutineにはまだfalse
が挿入されていないため、何も読み込めません。私の直感が正しいかどうかは分かりません。私はコードの周りに印字行を置いたが、それは少なくとも起こっているようだ。私もblチャネルの周りにifを置こうとしましたが、それは同じ問題で終わった。私もbl <- false
をif can {
ブロック内に移動しましたが、それも機能しませんでした。これをどうやって解決するのですか?
現在の解決策の問題は、b1チャンネルを送信する最後のゴルーチンが受信者が送信された値を取得するのを待つため、ゴルーチンが決して終了せず、全体を待っているメインのゴルーチンゴルーチンのグループ1がチャネルのバッファサイズである場合、バッファ付きチャネル(b1:= make(chan bool、1))を使用して固定できます。これはあなたのアプローチがちょうどうまくいくようにしますが、私の提案する解決策は、値がチャネルを介して送信される理由をより明示的だと思います。 –
恐ろしいです!この例をありがとう。それが本当に助けになりました。 – Soubriquet