Golang Go语言中使用有缓存的 chan,但 sync.WaitGroup 在 wait()时死住了

发布于 1周前 作者 sinazl 来自 Go语言
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

8 回复

// 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(),或者存在逻辑上的竞态条件。

以下是一些可能导致这种情况的原因及解决方案:

  1. 确保每个WaitGroup.Add(1)都有对应的WaitGroup.Done():检查所有启动的goroutine是否都在完成任务后调用了Done()。这是WaitGroup工作的基础,每个Add必须匹配一个Done

  2. 避免在channel操作中引发死锁:带缓存的channel在缓冲区满时会导致发送阻塞,在缓冲区空时会导致接收阻塞。确保发送和接收操作能够正确匹配,且不会因缓冲区大小限制而导致永久阻塞。

  3. 检查是否有goroutine泄露:有时,由于逻辑错误,某些goroutine可能未能启动或提前退出,导致Done()未被调用。使用日志或调试工具跟踪goroutine的生命周期。

  4. 使用select语句处理channel操作:在涉及多个channel操作时,使用select语句可以防止永久阻塞,因为select会选择一个可以立即进行的操作。

  5. 检查竞态条件:使用Go的竞态检测工具(go run -race)来检测代码中可能存在的竞态条件。

通过上述步骤,通常可以定位并解决WaitGroup.Wait()死锁的问题。如果问题依旧存在,建议仔细检查代码逻辑,或寻求社区帮助。

回到顶部