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

バージョン 1.1.2 (現在のリリース) の Go には、元の (最初のリリース以降) ゴルーチンの協調スケジューリングしかありません。コンパイラは、スケジューリング ポイントを挿入することで動作を改善します。メモリ モデルから推測すると、それらはチャネル操作の隣にあります。さらに、I/O が発生する場所など、よく知られているが意図的に文書化されていない場所にもあります。fmt.Printf最後は、コメントを外すとプログラムの動作が変わる理由を説明しています。そして、ところで、Go チップ バージョンは現在、プリエンプティブ スケジューラを備えています。

あなたのコードは、ゴルーチンの 1 つをデフォルトの選択ケースでビジー状態に保ちます。印刷なしで他のスケジューリング ポイントがないため、他のゴルーチンが進行する機会はありません (デフォルトの GOMAXPROCS=1 を想定)。

スピン (ビジー待機) を回避する方法でプログラムのロジックを書き直すことをお勧めします。考えられるアプローチの 1 つは、デフォルトのケースでチャネル送信を使用することです。そのためにバッファリングされたチャネルを使用することのおそらく良い副作用として、それから単純なリミッタを無料で取得できます。

于 2013-09-09T07:31:03.347 に答える