停止无限期写入通道的 goroutine

问题描述 投票:0回答:1

我有一个函数可以创建一个无限期地填充通道的 goroutine,例如:

func Foo() <-chan int {
  ch := make(chan int) 
  go func() {
    defer close(ch)
    for {
      ch <- 1
    } 
  }() 
  return ch
}

假设我们有一个消费者想在一段时间后停下来:

ch:=Foo() 
<-ch
<-ch
// done

现在我想清理 goroutine 资源,包括通道。我试图为此添加一个“完成”频道,但后来我遇到了僵局:

func Foo() (<-chan int, chan<- bool) {
  ch := make(chan int)
  done := make(chan bool)
  go func() {
    defer close(ch)
    for {
      select {
      case <-done:
          return
      default:
          ch <- 1
      }
    } 
  }() 
  return ch, done
}

func main() {
  ch, done := Foo()
  <-ch
  <-ch
  done <- true
  // HERE
}

现在,它似乎可以工作,但这只是因为程序退出,如果我将

// HERE
替换为一些io操作(例如:
http.Get("http://google.com")
),我将面临死锁(
fatal error: all goroutines are asleep - deadlock!
)。 我想知道是否有另一种方法来清理由
Foo
函数创建的生成的 goroutine 和通道。

go deadlock channels
1个回答
1
投票

只需在启动的 goroutine 中将

default
替换为
case

func Foo() (<-chan int, chan<- bool) {
  ch := make(chan int)
  done := make(chan bool)
  go func() {
    defer close(ch)
    for {
      select {
      case <-done:
          return
      case ch <- 1:
      }
    } 
  }() 
  return ch, done
}
© www.soinside.com 2019 - 2024. All rights reserved.