gpt4 book ai didi

go - 与 WaitGroup 的 channel 同步。关闭 channel 和 Waitgroup

转载 作者:行者123 更新时间:2023-12-01 20:24:14 24 4
gpt4 key购买 nike

我想了解 Goroutine 中的同步。我这里有一个代码,它在一个 channel 上写入从 0 到 4 的数字,完成后我使用 range 从 channel 读取并打印值。

下面的代码在我等待时使用 wg.Wait() 并在单独的 Goroutine 中关闭 channel 时工作正常。

package main

import (
"fmt"
"strconv"
"sync"
)

func putvalue(i chan string, value string, wg *sync.WaitGroup) {
i <- value
defer wg.Done()
}

func main() {
queue := make(chan string)
var wg sync.WaitGroup

for i := 0; i < 5; i++ {
wg.Add(1)
go putvalue(queue, strconv.Itoa(i), &wg)
}

go func() {
wg.Wait()
close(queue)
}()

for elem := range queue {
fmt.Println(elem)
}

}

https://play.golang.org/p/OtaRP3Mm4lk

但如果我使用完全相同的代码,但在主线程中等待并关闭 channel ,则会导致死锁。以下代码导致死锁。

package main

import (
"fmt"
"strconv"
"sync"
)

func putvalue(i chan string, value string, wg *sync.WaitGroup) {
i <- value
defer wg.Done()
}

func main() {
queue := make(chan string)
var wg sync.WaitGroup

for i := 0; i < 5; i++ {
wg.Add(1)
go putvalue(queue, strconv.Itoa(i), &wg)
}

wg.Wait()
close(queue)

for elem := range queue {
fmt.Println(elem)
}

}

https://play.golang.org/p/JXmdsdPKQPu

据我所知,在第二种情况下,主线程执行停止并等待,但这与在单独的 goroutine 中执行有何不同?请帮助我理解这一点。

最佳答案

将每个 goroutine 视为一个单独的人(或 gopher:https://blog.golang.org/gopher)可能会有所帮助。当你go f()你得到一个新的人/地鼠并给他们运行该功能的工作。所以,你有 5 个额外的 gophers 正在运行这个:

func putvalue(i chan string, value string, wg *sync.WaitGroup) {
i <- value
defer wg.Done()
}

5 个中的每一个都运行到它们到达 i <- value 的点线,然后他们停下来,等待 gopher 跑到 channel /邮箱的“获取”一侧,然后伸出手来获取字符串,这是进入 i 的那种包裹。 channel /邮箱。

(另外:defer wg.Done() 应该是函数的第一行,而不是最后一行。或者,将 wg.Done() 作为函数的最后一行。)

现在,如果此时你获得了第六只额外的地鼠并让他这样做:

{
wg.Wait()
close(queue)
}

他会在里面停下来 wg.Wait() , 等待。

您的主要 gopher 现在继续前往 for环形。这是从邮箱中读取的,也就是说,现在您的 main gopher 将他的手伸进邮箱/窗口,在 channel 的“get”端。五只等待中的地鼠中的一只终于可以将绳子交到您的地鼠手中了。您的主要 Gopher 获取字符串并将其带回您的 for环形。被阻止的五个地鼠之一现在可以执行他的 wg.Done()并过期(大概是去退休地鼠的快乐之地😀)。

您的主要 gopher 在 for 中继续循环,通过邮箱获取更多包裹。当他这样做时,等待邮箱“put”的四只地鼠完成并调用wg.Done()。 ,它计算工作组计数器。当计数达到零时,不再有等待将包裹放入邮箱的地鼠,但是现在正在 sleep 的地鼠,正在等待wg.Wait()。 ,被唤醒。所以他很快就会醒来并调用close .

如果他没有调用close然而,您的主要 gopher 在等待下一个包裹。所以只有剩下的一只地鼠可以做任何事情:他会完成收盘。或者,也许他醒得很快并且已经关闭了,但如果是这样,您的主要 gopher 已经看到邮箱窗口永远关闭了。无论哪种方式,您的主要 gopher 已经看到或将要看到邮箱窗口( channel )已关闭,并且 for循环将停止,您的主要地鼠将从 main 返回并前往快乐退休之地。

作为Burak Serdar noted ,虽然,没有单独的地鼠做 wg.Wait()其次是 close ,这是您的 main gopher 正在执行 wg.Wait() .所以他从来没有绕过for循环从(仍然打开的)邮箱/ channel 读取。你的五只地鼠正在 sleep ,等待一只地鼠 Handlebars 伸进邮箱去取他们的包裹。您的主要 gopher 正在 sleep ,等待 sync.WaitGroup 中的柜台下降到零。大家都睡了!

关于go - 与 WaitGroup 的 channel 同步。关闭 channel 和 Waitgroup,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59638898/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com