无限期地运行 Go 例程

Ale*_*ner 4 go

我有一个函数调用另一个返回 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())
        }
      }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Sud*_*han 7

当主协程main退出时,您可能产生的所有协程都将成为孤儿并最终死亡。

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

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

<-exit
Run Code Online (Sandbox Code Playgroud)

在最后而不是一个forselect循环。


haz*_*haz 5

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

采取这个代码片段:

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

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

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
}
Run Code Online (Sandbox Code Playgroud)