Go Playground和Go之间的差异在我的机器上?

时间:2016-04-18 23:06:14

标签: go goroutine go-playground

为了解决我对goroutines的一些误解,我去了Go操场并跑了this code

package main

import (
    "fmt"
)

func other(done chan bool) {
    done <- true
    go func() {
        for {
            fmt.Println("Here")
        }
    }()
}

func main() {
    fmt.Println("Hello, playground")
    done := make(chan bool)
    go other(done)
    <-done
    fmt.Println("Finished.")
}

正如我所料,Go操场回来时出现错误:过程耗时太长

这似乎暗示在other内创建的goroutine会永远运行。

但是当我在自己的机器上运行相同的代码时,我几乎立即得到了这个输出:

Hello, playground.
Finished.

这似乎意味着当主要的goroutine结束时other内的goroutine退出。 这是真的吗?或主要的goroutine完成,而另一个goroutine继续在后台运行?

2 个答案:

答案 0 :(得分:1)

您所看到的内容的解释:

在Go Playground,GOMAXPROCS1proof)。

这意味着一次执行一个goroutine,如果该goroutine没有阻塞,则不会强制调度程序切换到其他goroutine。

您的代码(与每个Go应用程序一样)以执行main()函数(主要goroutine)的goroutine开头。它启动另一个执行other()函数的goroutine,然后从done通道接收 - 阻塞。因此调度程序必须切换到另一个goroutine(执行other()函数)。

当您在other()频道上发送值时,在done功能中,这会使当前(other())和main goroutine运行。调度程序选择继续运行other(),由于GOMAXPROCS=1main()不会继续运行。现在other()启动另一个执行无限循环的goroutine。调度程序选择执行此goroutine,这将永远进入阻塞状态,因此main()不会继续。

然后Go Playground的沙箱超时就是一个赦免:

  

过程花了太长时间

请注意,Go Memory Model仅保证某些事件在其他事件发生之前发生,您无法保证如何执行2个并发的goroutine。这使得输出不确定。

您不会质疑任何不违反Go Memory Model的执行顺序。如果希望执行到达代码中的某些点(执行某些语句),则需要显式同步(需要同步goroutine)。

另请注意,Go Playground上的输出已缓存,因此如果再次运行该应用程序,它将不会再次运行,而是会立即显示缓存的输出。如果您更改代码中的任何内容(例如插入空格或注释),然后再次运行它,那么它将被编译并再次运行。您会通过增加的响应时间来注意到它。使用当前版本(Go 1.6),您每次都会看到相同的输出。

在本地(在您的计算机上)运行:

当您在本地运行时,很可能GOMAXPROCS将大于1,因为它默认为可用的CPU核心数(自Go 1.5起)。因此,如果你有一个执行无限循环的goroutine并不重要,另一个goroutine将同时执行,这将是main(),当main()返回时,你的程序终止;它不会等待其他非main goroutines完成(参见Spec: Program execution)。

另请注意,即使您将GOMAXPROCS设置为1,您的应用很可能会在“短暂”时间内退出,因为调度程序的实现将切换到其他goroutines而不仅仅是执行无限循环永远(但是,如上所述,这是非确定性的)。当它发生时,它将是main() goroutine,因此当main()完成并返回时,您的应用终止。

在Go Playground上玩你的应用程序:

如前所述,Go Goground默认GOMAXPROCS1。但是,允许将其设置为更高的值,例如:

runtime.GOMAXPROCS(2)

如果没有显式同步,执行仍然是不确定的,但是你会观察到不同的执行顺序和终止,而不会遇到超时:

Hello, playground
Here
Here
Here
...
<Here is printed 996 times, then:>
Finished.

Go Playground上尝试此变体。

答案 1 :(得分:0)

您将在屏幕上看到的内容是不确定的。或者更确切地说,如果您传递给频道的true值被延迟,您会看到一些&#34;此处&#34;。

但通常Stdout是缓冲的,这意味着它不会立即打印,但数据会被累积,并且在达到最大缓冲区大小后会被打印出来。在你的情况下,&#34; here&#34;打印主要功能已经完成,因此过程结束。

经验法则是:主要功能必须是活着的,否则所有其他goroutine都会被杀死。