【问题标题】:Same Golang code different output, why?相同的 Golang 代码不同的输出,为什么?
【发布时间】:2012-11-07 02:50:40
【问题描述】:

我正在尝试执行来自 golang.org 的示例:http://tour.golang.org/#63

  • 我已更改代码以测试 Gosched 的功能。*

你可以看到那里的输出:

hello
hello
hello
hello
hello

但是当我将这些代码复制到我的 Mac OS X 10.8(Go 版本 1.0.3)时,输出发生了变化: xxxxxx$ 去版本 去版本去1.0.3 xxxxxx$ 去运行 goroutine.go 你好 世界 你好 世界 你好 世界 你好 世界 你好 世界

根据这个answer,我应该使用runtime.GoSched,但实际上我不需要。所以我相信出了点问题。

请帮我解决这个问题,非常感谢。

【问题讨论】:

  • 我去了tour.golang.org/#63,结果是 hello\nworld\n 按预期重复了 5 次。您在本地运行的示例使用大写字母打印“World”,这意味着您没有复制和粘贴示例代码。我假设你在某个地方有错误。请记住重置幻灯片,以便您拥有原始示例代码。
  • 感谢@StephenWeinberg,我确定这些代码是相同的(我已经更改了输出字以进行测试,但现在我将它们改回来了)。

标签: concurrency go


【解决方案1】:

这里的问题是你有两个不同的实现。

在本地,每次调用 fmt.Println 时,您的代码都会让给调度程序。 Println 写入执行系统调用的标准输出。所有系统调用都以相同的方式产生 runtime.Gosched。

play.golang.org 是一个黑盒子。我们实际上并不知道它是如何工作的。但是,从您给出的示例中,似乎 play 在调用 fmt.Println 时不会执行系统调用。这是有道理的。他们可能用缓冲区替换了 os.Stdout 来保存打印的内容。

【讨论】:

  • 你的意思是 所有系统调用产生相同的方式 runtime.Gosched 做 ?你确定吗?如果它是真的,那么我们什么时候应该使用 runtime.Gosched ?谢谢:D
  • 是的,在当前的实现中,系统调用会产生。您永远不需要在实际程序中使用 runtime.Gosched。它仅适用于非常紧凑的处理循环。非缓冲通道使用、IO 或内存分配将导致产量。在实际程序中,我从未使用过 Gosched。
  • @MrROY,似乎系统调用上的收益是最近的变化。我当然能够在旧版本的 Go 编译器上重现类似游戏的行为。这确实使Gosched 在大多数普通代码中过时了。
  • 这不是新的,系统调用总是让步,它是防止系统调用阻塞所有 goroutine 继续运行的机制的一部分。大多数代码从不需要 Gosched。
【解决方案2】:

Go Tour 代码只是一个介绍性示例。代码简单且不正确。 GoTour63 给出以下输出(添加了行号):

1 hello
2 world
3 hello
4 world
5 hello
6 world
7 hello
8 world
9 hello

程序应该打印 10 行。请注意,缺少10 world 行。也许这是故意的,用户应该注意到这一点并调查问题的原因。语言规范中的Program execution 部分声明如下:

当 main 函数返回时,程序退出。它不会等待其他(非主)goroutine 完成。

此语句解释了为什么程序打印的行数少于 10 行。

正确的 Go 程序通常使用:

【讨论】:

    【解决方案3】:

    这是因为您正在调用一个在您的编程环境之外运行的 goroutine。从字面上看,两个线程同时执行,并且输出是随机的。

    【讨论】:

      猜你喜欢
      • 2019-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-23
      • 2021-11-12
      • 2016-09-16
      • 2022-01-04
      相关资源
      最近更新 更多