Golang Go语言中使用有缓存的 chan,但 sync.WaitGroup 在 wait()时死住了
func fetch(url string, channel chan string, wg sync.WaitGroup) {
defer wg.Done()
resp, err := http.Get(url)
if (err != nil) || (resp.StatusCode != http.StatusOK) {
temp := fmt.Sprintf("Cannot fetch %s", url)
channel <- temp
fmt.Println("put one")
}
}
func preFetchAd(ad *Ad) error {
var wg sync.WaitGroup
count := 0
count = count + len(ad.Urls)
for _, urls := range ad.Urls2 {
count = count + len(urls)
}
c := make(chan string, count)
//fmt.Println(count)
errs := []string{}
for _, url := range ad.Urls {
wg.Add(1)
go fetch(url.L, c, wg)
}
for _, urls := range ad.Urls2 {
for _, url := range urls {
wg.Add(1)
go fetch(url.L, c, wg)
}
}
wg.Wait()
close(c)
for err := range c {
errs = append(errs, err)
}
if len(errs) == 0 {
return nil
}
e := strings.Join(errs, "\n")
return errors.New(e)
}
我先预算了个数,创建了足够缓存的 chan,但似乎依旧阻塞了?
Golang Go语言中使用有缓存的 chan,但 sync.WaitGroup 在 wait()时死住了
更多关于Golang Go语言中使用有缓存的 chan,但 sync.WaitGroup 在 wait()时死住了的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
// wg 要传指针
func fetch(url string, channel chan string, wg sync.WaitGroup)
更多关于Golang Go语言中使用有缓存的 chan,但 sync.WaitGroup 在 wait()时死住了的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
发个最小可重现代码,不然别人怎么帮你调?
1.一楼 说的不错
2.另外 resp.body.Close 不要忘记
3.这种问题可以通过加写日志来定位
wg := new(sync.WaitGroup)
不然传参数的时候就是复制了,文档里说了不能复制
用 go tool vet 也能发现错误
例如下面的代码
package main
import "sync"
func main() {
var wg sync.WaitGroup
foo(wg)
}
func foo(wg sync.WaitGroup) {
}
执行
go tool vet a.go
输出
a.go:7: call of foo copies lock value: sync.WaitGroup contains sync.noCopy
a.go:10: foo passes lock by value: sync.WaitGroup contains sync.noCopy
善用 go vet,可以提前发现这些问题
main.go:5: fetch passes lock by value: sync.WaitGroup contains sync.noCopy
谢谢 没写多久 golang 都不知道有这个工具
在Go语言中,使用带缓存的channel(channel with buffer)与sync.WaitGroup
时,如果在WaitGroup.Wait()
处发生死锁,通常意味着有一些goroutine没有正确调用WaitGroup.Done()
,或者存在逻辑上的竞态条件。
以下是一些可能导致这种情况的原因及解决方案:
-
确保每个
WaitGroup.Add(1)
都有对应的WaitGroup.Done()
:检查所有启动的goroutine是否都在完成任务后调用了Done()
。这是WaitGroup
工作的基础,每个Add
必须匹配一个Done
。 -
避免在channel操作中引发死锁:带缓存的channel在缓冲区满时会导致发送阻塞,在缓冲区空时会导致接收阻塞。确保发送和接收操作能够正确匹配,且不会因缓冲区大小限制而导致永久阻塞。
-
检查是否有goroutine泄露:有时,由于逻辑错误,某些goroutine可能未能启动或提前退出,导致
Done()
未被调用。使用日志或调试工具跟踪goroutine的生命周期。 -
使用
select
语句处理channel操作:在涉及多个channel操作时,使用select
语句可以防止永久阻塞,因为select
会选择一个可以立即进行的操作。 -
检查竞态条件:使用Go的竞态检测工具(
go run -race
)来检测代码中可能存在的竞态条件。
通过上述步骤,通常可以定位并解决WaitGroup.Wait()
死锁的问题。如果问题依旧存在,建议仔细检查代码逻辑,或寻求社区帮助。