首页  >  文章  >  后端开发  >  在 Go 中使用带有外部函数的sync.WaitGroup时如何避免死锁?

在 Go 中使用带有外部函数的sync.WaitGroup时如何避免死锁?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-11-05 22:03:02877浏览

How to Avoid Deadlocks When Using sync.WaitGroup with External Functions in Go?

将sync.WaitGroup与外部函数结合使用的最佳实践

在处理Go中的并发时,有效利用sync.WaitGroup至关重要。本文解决了将等待组作为参数传递给外部函数时出现的常见问题。

问题:

考虑以下代码:

<code class="go">package main

import (
    "fmt"
    "sync"
)

func main() {
    ch := make(chan int)
    var wg sync.WaitGroup
    wg.Add(2)
    go Print(ch, wg) //
    go func(){

        for i := 1; i <= 11; i++ {
            ch <- i
        }

        close(ch)
        defer wg.Done()


    }()

    wg.Wait() //deadlock here
}

// Print prints all numbers sent on the channel.
// The function returns when the channel is closed.
func Print(ch <-chan int, wg sync.WaitGroup) {
    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }
    defer wg.Done()
}</code>

这段代码中,在指定行发生死锁,导致程序只打印从1到10,而不是到达11。该错误源于将sync.WaitGroup的副本传递给Print方法,这阻碍了对其 Done 方法的预期调用。

解决方案 1:

要解决此问题,请将指针传递给等待组:

<code class="go">package main

import (
    "fmt"
    "sync"
)

func main() {    
    ch := make(chan int)

    var wg sync.WaitGroup
    wg.Add(2)    

    go Print(ch, &wg)

    go func() {  
        for i := 1; i <= 11; i++ {
            ch <- i
        }
        close(ch)
        defer wg.Done()
    }()          

    wg.Wait() //deadlock here
}                

func Print(ch <-chan int, wg *sync.WaitGroup) {
    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }            
    defer wg.Done()
}</code>

传递 wg 的地址可以确保 Print 方法调用 main 函数中等待的等待组上的 Done 方法。

解决方案 2:简化的 Print 方法

或者,可以通过删除 WaitGroup 参数来简化 Print 方法,因为它不需要了解任何等待操作:

<code class="go">package main

import (
    "fmt"
)

func main() {    
    ch := make(chan int)
    go func() {  
        for i := 1; i <= 11; i++ {
            ch <- i
        }
        close(ch)
    }()          

    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }            
}                </code>

在这种情况下,主 goroutine 直接接收通道并打印它的值不涉及等待组。这种方法保留了所需的功能,并消除了 Print 方法中对 WaitGroup 管理的需要。

结论:

当将sync.WaitGroup 作为参数传递给外部函数时,确保函数接收到正在等待的等待组的正确引用至关重要。重构函数以直接处理等待组或传递指针到等待组可以有效防止死锁错误并确保正确的并发控制。

以上是在 Go 中使用带有外部函数的sync.WaitGroup时如何避免死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn