0

我的 Go 代码中有非常奇怪的行为。总的要点是,当我有

for {
  if messagesRecieved == l {
    break
  }
  select {
  case result := <-results:
    newWords[result.index] = result.word
    messagesRecieved += 1
  default:
    // fmt.Printf("messagesRecieved: %v\n", messagesRecieved)
    if i != l {
      request := Request{word: words[i], index: i, thesaurus_word: results}
      requests <- request
      i += 1
    }
  }
}

程序冻结并且无法前进,但是当我取消注释 fmt.Printf 命令时,程序运行正常。您可以在此处查看整个代码。有谁知道是什么导致了这种行为?

4

1 回答 1

2

Go 在 1.1.2 版本(当前版本)中仍然只有原始的(自初始版本以来)goroutines 的协作调度。编译器通过插入调度点来改进行为。从内存模型推断,它们与通道操作相邻。此外,还存在于一些众所周知但故意未记录的地方,例如 I/O 发生的地方。最后解释了为什么取消注释fmt.Printf会改变程序的行为。而且,顺便说一句,Go 提示版本现在具有抢先调度程序。

您的代码使您的一个 goroutine 忙于处理默认选择案例。由于没有其他调度点没有打印,没有其他 goroutine 有机会取得进展(假设默认 GOMAXPROCS=1)。

我建议以一种避免旋转(忙等待)的方式重写程序的逻辑。一种可能的方法是在默认情况下使用通道发送。作为使用缓冲通道的一个很好的副作用,人们可以免费获得一个简单的限制器。

于 2013-09-09T07:31:03.347 回答