Golang中使用WaitGroup时所有goroutine都处于休眠状态的问题
Golang中使用WaitGroup时所有goroutine都处于休眠状态的问题 我正在探索如何使用 WaitGroup 来等待所有 goroutine 完成。这是我的代码:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(3)
go one(wg)
go two(wg)
go three(wg)
wg.Wait()
}
func one(wg sync.WaitGroup) {
defer wg.Done()
time.Sleep(5 * time.Second)
fmt.Println("One")
}
func two(wg sync.WaitGroup) {
defer wg.Done()
time.Sleep(7 * time.Second)
fmt.Println("Two")
}
func three(wg sync.WaitGroup) {
defer wg.Done()
time.Sleep(3 * time.Second)
fmt.Println("Three")
}
在所有 goroutine 都打印完毕后,我一直收到这个错误“所有 goroutine 都已休眠 - 死锁”。我无法理解这里出了什么问题——没有涉及任何通道——这只是一个简单的流程。我遗漏了什么?
更多关于Golang中使用WaitGroup时所有goroutine都处于休眠状态的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
谢谢。
更多关于Golang中使用WaitGroup时所有goroutine都处于休眠状态的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你的代码中存在一个关键问题:sync.WaitGroup 应该通过指针传递,而不是值传递。当你将 WaitGroup 作为值传递给 goroutine 函数时,每个 goroutine 都会获得该 WaitGroup 的副本,导致主 goroutine 中的原始 WaitGroup 永远不会收到 Done() 调用,从而造成死锁。
以下是修正后的代码:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(3)
go one(&wg)
go two(&wg)
go three(&wg)
wg.Wait()
fmt.Println("All goroutines completed")
}
func one(wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(5 * time.Second)
fmt.Println("One")
}
func two(wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(7 * time.Second)
fmt.Println("Two")
}
func three(wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(3 * time.Second)
fmt.Println("Three")
}
关键修改:
- 将函数签名改为接收
*sync.WaitGroup指针类型 - 在调用 goroutine 时传递
&wg地址 - 所有 goroutine 现在操作的是同一个
WaitGroup实例
运行结果:
Three
One
Two
All goroutines completed
另一种常见的写法是使用闭包来避免传递 WaitGroup:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
tasks := []func(){
func() {
time.Sleep(5 * time.Second)
fmt.Println("One")
},
func() {
time.Sleep(7 * time.Second)
fmt.Println("Two")
},
func() {
time.Sleep(3 * time.Second)
fmt.Println("Three")
},
}
wg.Add(len(tasks))
for _, task := range tasks {
go func(t func()) {
defer wg.Done()
t()
}(task)
}
wg.Wait()
fmt.Println("All goroutines completed")
}
这种闭包方式让代码更简洁,同时避免了参数传递的问题。


