doubu1970 2016-04-18 23:06
浏览 30
已采纳

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

To settle some misunderstandings I have about goroutines, I went to the Go playground and ran 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.")
}

As I expected, Go playground came back with an error: Process took too long.

This seems to imply that the goroutine created within other runs forever.

But when I run the same code on my own machine, I get this output almost instantaneously:

Hello, playground.
Finished.

This seems to imply that the goroutine within other exits when the main goroutine finishes. Is this true? Or does the main goroutine finish, while the other goroutine continues to run in the background?

  • 写回答

2条回答 默认 最新

  • donglei3370 2016-04-19 00:31
    关注

    Explanation of what you see:

    On the Go Playground, GOMAXPROCS is 1 (proof).

    This means one goroutine is executed at a time, and if that goroutine does not block, the scheduler is not forced to switch to other goroutines.

    Your code (like every Go app) starts with a goroutine executing the main() function (the main goroutine). It starts another goroutine that executes the other() function, then it receives from the done channel - which blocks. So the scheduler must switch to the other goroutine (executing other() function).

    In your other() function when you send a value on the done channel, that makes both the current (other()) and the main goroutine runnable. The scheduler chooses to continue to run other(), and since GOMAXPROCS=1, main() is not continued. Now other() launches another goroutine executing an endless loop. The scheduler chooses to execute this goroutine which takes forever to get to a blocked state, so main() is not continued.

    And then the timeout of the Go Playground's sandbox comes as an absolution:

    process took too long

    Note that the Go Memory Model only guarantees that certain events happen before other events, you have no guarantee how 2 concurrent goroutines are executed. Which makes the output non-deterministic.

    You are not to question any execution order that does not violate the Go Memory Model. If you want the execution to reach certain points in your code (to execute certain statements), you need explicit synchronization (you need to synchronize your goroutines).

    Also note that the output on the Go Playground is cached, so if you run the app again, it won't be run again, but instead the cached output will be presented immediately. If you change anything in the code (e.g. insert a space or a comment) and then you run it again, it then will be compiled and run again. You will notice it by the increased response time. Using the current version (Go 1.6) you will see the same output every time though.

    Running locally (on your machine):

    When you run it locally, most likely GOMAXPROCS will be greater than 1 as it defaults to the number of CPU cores available (since Go 1.5). So it doesn't matter if you have a goroutine executing an endless loop, another goroutine will be executed simultaneously, which will be the main(), and when main() returns, your program terminates; it does not wait for other non-main goroutines to complete (see Spec: Program execution).

    Also note that even if you set GOMAXPROCS to 1, your app will most likely exit in a "short" time as the scheduler imlementation will switch to other goroutines and not just execute the endless loop forever (however, as stated above, this is non-deterministic). And when it does, it will be the main() goroutine, and so when main() finishes and returns, your app terminates.

    Playing with your app on the Go Playground:

    As mentioned, by default GOMAXPROCS is 1 on the Go Playground. However it is allowed to set it to a higher value, e.g.:

    runtime.GOMAXPROCS(2)
    

    Without explicit synchronization, execution still remains non-deterministic, however you will observe a different execution order and a termination without running into a timeout:

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

    Try this variant on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥30 eclipse开启服务后,网页无法打开
  • ¥30 雷达辐射源信号参考模型
  • ¥15 html+css+js如何实现这样子的效果?
  • ¥15 STM32单片机自主设计
  • ¥15 如何在node.js中或者java中给wav格式的音频编码成sil格式呢
  • ¥15 不小心不正规的开发公司导致不给我们y码,
  • ¥15 我的代码无法在vc++中运行呀,错误很多
  • ¥50 求一个win系统下运行的可自动抓取arm64架构deb安装包和其依赖包的软件。
  • ¥60 fail to initialize keyboard hotkeys through kernel.0000000000
  • ¥30 ppOCRLabel导出识别结果失败