Я пишу этот примерный код, чтобы научить себя, как делиться каналами через параллельные goroutines, и я попадаю в состояние гонки. Программа должна запускать как можно больше goroutines, так как в системе есть доступные процессоры. Первый goroutine для доступа к каналу bl немедленно устанавливает, что канал содержит false, так что никакие другие goroutines не могут получить доступ к циклу, который находится по каналу st. Остальные goroutines должны заканчиваться как первая goroutine, которая обратилась к каналу bl, считывает с канала st и печатает каждое значение.Состояние голангского гонорара при совместном использовании каналов через параллельные goroutines
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
Я не знаю, как справиться с этим состоянием гонки для канала бл. Кажется, что последний goroutine застрял, пытаясь прочитать из канала bl, но нет ничего, чтобы читать это, потому что goroutine перед ним еще не вставил false
. Не уверен, что моя интуиция верна. Я разместил строки печати вокруг кода, и это, по-видимому, происходит по крайней мере. Я также попытался установить if, если вокруг канала bl, но это закончилось тем же вопросом. Я также переместил bl <- false
внутри блока if can {
, но это тоже не сработало. Как это исправить?
Проблема с вашим текущим решением заключается в том, что последний goroutine при отправке по каналу b1 будет ожидать, что получатель получит отправленное значение, так что goroutine никогда не выйдет, ни главная горутин, которая ждет целого группа горти. Он может быть исправлен с использованием буферизованного канала (b1: = make (chan bool, 1)), когда 1 является размером буфера канала. Это заставит ваш подход работать, но я думаю, что мое предлагаемое решение более подробно объясняет, почему значения передаются по каналам –
Awesome! Спасибо за пример. Это действительно помогло. – Soubriquet