gpt4 book ai didi

go - 尝试使用 close(ch) 结束 goroutine 但最终会无限运行

转载 作者:IT王子 更新时间:2023-10-29 02:28:14 26 4
gpt4 key购买 nike

我正在尝试在另一个 goroutine 关闭 channel 后结束多个 goroutine。但是,在收到关闭信号后,我将陷入无限循环。我不明白为什么。

我知道使用 context.Context 是可行的,但我是通过关闭 channel 来尝试的。

去 Playground :https://play.golang.org/p/C6pcYgGLnG9

package main

import (
"fmt"
"time"
"sync"
)


func runner(id int, ch <-chan struct{}, wg *sync.WaitGroup) {
for {
select {
case <-time.Tick(time.Second):
fmt.Println("worker ", id)
case <- ch:
fmt.Println("closing worker ", id)
break
}
}

wg.Done()

}

func main() {
fmt.Println("Hello, playground")
ch := make(chan struct{})
var wg sync.WaitGroup

wg.Add(1)
go runner(1, ch, &wg)

wg.Add(1)
go runner(2, ch, &wg)

time.Sleep(5*time.Second)

close(ch)

wg.Wait()
}

最佳答案

问题是你的break的范围:

func runner(id int, ch <-chan struct{}, wg *sync.WaitGroup) {
for {
select {
case <-time.Tick(time.Second):
fmt.Println("worker ", id)
case <- ch:
fmt.Println("closing worker ", id)
break
}
}

wg.Done()
}

您想跳出 for 循环,但实际上只是跳出 select。要解决此问题,您有两种选择:

  1. 为您的 for 循环添加一个标签,并明确地中断它:

    func runner(id int, ch <-chan struct{}, wg *sync.WaitGroup) {
    loop: // <---------- add a label
    for {
    select {
    case <-time.Tick(time.Second):
    fmt.Println("worker ", id)
    case <-ch:
    fmt.Println("closing worker ", id)
    break loop // <---------- and break from it explicitly
    }
    }

    wg.Done()
    }
  2. 可能是更惯用和更可靠的解决方案,只需在完成后返回即可。这意味着必须推迟 wg.Done() 调用。

    func runner(id int, ch <-chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done() // <--- Defer the wg.Done() call, so it happens on return
    for {
    select {
    case <-time.Tick(time.Second):
    fmt.Println("worker ", id)
    case <-ch:
    fmt.Println("closing worker ", id)
    return // <--- replace `break` with `return`
    }
    }
    }

关于go - 尝试使用 close(ch) 结束 goroutine 但最终会无限运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57178032/

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