ポーラー関数(メイン関数から受信する)の「in」チャネルが3つのポーラーgoルーチンのみを実行する場合、プログラムはどのようにポーラー関数を無限に実行しますか?
したがって、最初にプログラムは 2 つのポーラーを作成します。
for i := 0; i < numPollers; i++ {
go Poller(pending, complete, status)
}
次に、3 つのリソースを保留に送信します。
for _, url := range urls {
pending <- &Resource{url: url}
}
すべてのポーラーは保留中から読み取り、リソースをポーリングします。
for r := range in {
s := r.Poll()
status <- State{r.url, s}
out <- r
}
このコードは無限に実行されるように見えますが、通常、キューからの読み取りをブロックしています。したがって、このループは次の値が表示されるのを待ちます。
実際にそれを乗り越えてみましょう:
- リソースを読み取る 2 つのポーラーがあります。
- プログラムは最初のリソースをキューに送信します。
- ポーラーの 1 つがリソースを取得し、プールを開始します。もう一人は待っています。
- ある時点で、プログラムは新しいリソースをキューに送信します。
- 最初のポーラーがビジーであるため、2 番目のポーラーはブロックが解除され、ポーリングを開始します。
- プログラムは 3 番目のリソースを送信し、2 つのポーラーがビジーであるためブロックします。
- ポーラーの 1 つが完了すると、最後のリソースを取得して続行します。
- その間に、メイン プログラムは完全なキューから値を読み取ります。
for r := range in { s := r.Poll() status <- State{r.url, s} out <- r }
このコードはどのように無限に実行されますか? 「in」チャネルをループし、「in」が保留中のキューからリソースを取得する場合、数回の反復後に終了する必要があります。これはまさに私が理解していない部分だと思います。
正確には、キューin
からリソースを取得しません。キューです。キュー (または私が同じ意味で使用するチャネル) は、closeを呼び出すことで閉じることができますが、明示的に閉じられない限り、生きていると見なされます。それからの読み取りは、次の値が与えられるまで現在のゴルーチンをブロックします。そしてゴロチン再開。pending
in
pending
チャンネルというと要素数が固定された配列のようなものだと思い込んでいると思います。ではない。要素の数が無限であるが、例外をスローする可能性のある読み取りをブロックする配列が好きであると考えてください (概念に慣れていない場合は、キューを閉じることの大まかな近似です)。