【问题标题】:Running a Go routine indefinitely无限期运行 Go 例程
【发布时间】:2017-05-18 06:23:20
【问题描述】:

我有一个函数调用另一个返回 chan 数组的函数。我目前有一个 for 循环遍历数组中的范围,它运行程序无限期地输出通道更新作为通过。

func getRoutes() {
      for r := range rtu {
        if r.Type == 24 {
          fmt.Printf("Route added: %s via %s\n",r.Dst.String(),r.Gw.String())
        } else if r.Type == 25 {
          fmt.Printf("Route deleted: %s via %s\n",r.Dst.String(),r.Gw.String())
        }
      }
}

当我从 main() 调用 getRoutes() 时,一切都按计划进行,但它阻塞了应用程序。我尝试从main() 调用go getRoutes(),尽管看起来好像根本没有调用该函数。

如何使用 go 例程以非阻塞方式在后台运行此函数?

【问题讨论】:

标签: go


【解决方案1】:

main 的主 goroutine 退出时,您可能生成的所有 goroutine 都将成为孤立的并最终死亡。

您可以使用for {} 无限循环保持主 goroutine 永远运行,但您可能希望保留一个退出通道:

exit := make(chan string)

// Spawn all you worker goroutines, and send a message to exit when you're done.

for {
    select {
    case <-exit:
        os.Exit(0)
    }
}

更新: Cerise Limón 指出 goroutine 在 main 退出时会立即被杀死。我认为这应该是官方规定的行为。

另一个更新:当您有多种退出方式/多个退出通道时,for-select 效果更好。对于单个退出通道,您可以这样做

<-exit

在末尾而不是 forselect 循环。

【讨论】:

  • select 语句出现语法错误:syntax error: unexpected semicolon or newline, expecting comma or }
  • 认为我在 case 语句的末尾漏掉了一个冒号。
  • 更准确地说,当main 函数返回时程序退出。 goroutines 不会继续处于最终死亡的孤立状态。当程序退出时,进程中的所有执行都会停止。
  • 我也是这么想的,但是我看到了一些奇怪的行为——goroutines 在 main 退出后很久才记录到 STDOUT。也许go test --race 只是把程序放在后台什么的,或者在一个工具中运行 main。
  • 另外,你推荐使用for {}也是不正确的,因为忙循环总是编程错误,它浪费了100%的CPU,最终会导致运行时调度程序挂起.
【解决方案2】:

虽然其他人已经回答了这个问题,但我认为他们的解决方案在某些情况下可以简化。

取这个代码sn-p:

func main() {
    go doSomething()
    fmt.Println("Done.")
}

func doSomething() {
     for i := 0; i < 10; i++ {
        fmt.Println("Doing something...")
        time.Sleep(time.Second)
     }
}

main() 开始执行时,它会生成一个线程来并发执行doSomething()。然后它立即执行fmt.Println("Done."),然后main() 结束。

main() 完成时,所有其他 goroutine 将成为孤立的,并死掉。

为了避免这种情况,我们可以在 main() 的末尾放置一个阻塞操作,等待来自 goroutine 的输入。使用频道最容易做到这一点:

var exit = make(chan bool)

func main() {
    go doSomething()
    <-exit // This blocks until the exit channel receives some input
    fmt.Println("Done.")
}

func doSomething() {
     for i := 0; i < 10; i++ {
        fmt.Println("Doing something...")
        time.Sleep(time.Second)
     }
     exit<-true // Notify main() that this goroutine has finished
}

【讨论】:

    【解决方案3】:

    您的 main()getRoutes()-goroutine 完成之前返回。当main() 返回时,程序退出,从而杀死所有正在运行的 goroutine。 (main() 也完全有可能在 goroutine 有机会被 go runtime 调度之前返回。)

    如果您希望main()(或任何其他函数)等待一组 goroutine 完成,您必须让函数以某种方式显式等待。有多种方法可以做到这一点。 sync.WaitGroup.Wait() 可用于等待一组 goroutine 完成。你也可以在 goroutine 完成时使用通道进行通信。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-04
      • 2023-01-12
      • 2010-09-20
      • 2012-01-30
      • 2022-06-22
      • 1970-01-01
      相关资源
      最近更新 更多