英文:
How to execute multiple goroutines in parallel without a Deadlock
问题
所以我一直在尝试使用WaitGroup并行运行多个goroutine。无论我尝试什么,最终都会出现"fatal error: all goroutines are asleep - deadlock!"的错误。
这是我现在的代码:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go func() {
defer wg.Done()
wait(v, ch)
}()
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}
然而,这导致了死锁,我无法弄清楚原因。
我一直在尝试使用以下代码在WaitGroup之后读取值:
close(ch)
for v := range ch {
fmt.Println(v)
}
然而,似乎它甚至无法达到这部分。
谢谢!
英文:
So I have been trying to run mutliple goroutines in parallel using a WaitGroup. Whatever I try I always end up with a "fatal error: all goroutines are asleep - deadlock!"
This is what my code looks like right now:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go func() {
defer wg.Done()
wait(v, ch)
}()
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}
However this results in a deadlock and I can't figure out why.
I have been trying to read the values after the WaitGroup with the following code:
close(ch)
for v := range ch {
fmt.Println(v)
}
However it seems it wouldn't even reach this part.
Thank you!
答案1
得分: 1
在所有的工作线程完成后,你需要关闭工作通道。你现在是在主goroutine中立即关闭它。
所以你需要这样做:
go func() {
wg.Wait()
close(ch)
}()
另外,你的等待函数已经接受了一个time.Duration
类型的参数,所以在那一点上它应该是真实的时间,而不是乘以time.Second
。如果你想传入以秒为单位的值,考虑将输入类型更改为int
,以避免混淆。
英文:
You need to close the worker channel after all the workers are done. You are closing it immediately from the main goroutine.
So do this:
go func() {
wg.Wait()
close(ch)
}()
Also your wait function already takes a time.Duration
so really it should be in the real time at that point & not multiplied by time.Second
. if you want to pass in units of seconds, consider changing the input type to int
to avoid confusion.
答案2
得分: 1
代码存在两个问题:
- 必须在所有go协程完成后才能关闭通道。
- 在迭代过程中,v的值丢失了。
在Go语言中,for循环会重用v,因此所有的go协程在等待调用时都会有相同的值。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
v := v // <- 这里
go func() {
defer wg.Done()
wait(v, ch)
}()
}
go func() { // 在go协程完成后关闭通道
wg.Wait()
close(ch)
}()
for v := range ch { // 循环直到通道关闭
fmt.Println(v)
}
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}
英文:
There are two problems withe the code:
- You must close the channel only after all go-routines have finished
- The value of v is being lost during the iteration
In go, the for loop will reuse v, so all go-routines will have the same value on the wait call.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
v := v // <- this
go func() {
defer wg.Done()
wait(v, ch)
}()
}
go func() { // Close the channel only after go-routines finish
wg.Wait()
close(ch)
}()
for v := range ch { // Will loop until channel is closed
fmt.Println(v)
}
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论