去无限循环中显示奇怪的行为

时间:2013-09-09 07:01:43

标签: go channel

我的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命令时,程序运行正常。您可以看到整个代码here。有谁知道是什么导致了这种行为?

1 个答案:

答案 0 :(得分:2)

进入版本1.1.2(当前版本)仍然只有原始(自首次发布以来)goroutines的协作调度。编译器通过插入调度点来改进行为。从内存模型推断,它们是通道操作的旁边。另外还有一些众所周知但有意无证的地方,例如I / O发生的地方。最后一个解释了为什么取消注释fmt.Printf会改变程序的行为。而且,顺便说一下,Go tip版本现在是一个抢占式调度程序。

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

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