9

go がオーディオ/ビデオ アプリケーションの可能なオプションであるかどうかを評価するために、go でのメッセージ パッシングが、ブロックされない進行の保証 (障害がない、ロックがない、または待機がない) を満たしているかどうかを知りたいです。特に、次のシナリオが該当します。

シングル プロデューサー シングル コンシューマー:

2 つのスレッドが共有チャネルを使用して通信します。スレッド A は非同期送信のみを行い、スレッド B は非同期受信のみを行います。OS スケジューラーがスレッド A を「考えられる最悪の瞬間」に無期限に中断することを決定したとします。スレッド B は、制限された数の CPU サイクルで受信操作を完了することが保証されていますか、それともスレッド A が OS がスレッド A を再開するのを待つ必要がある状態にスレッド A がチャネルを入れることができる (理論的な) 可能性はありますか?

複数のプロデューサー:

いくつかのスレッド A1、A2、A3、... は、共有チャネルを使用して 1 つ以上の他のスレッドと通信します。スレッド Ai は非同期送信のみを行います。A2、A3、... が OS スケジューラによって「考えられる最悪の瞬間」に無期限に中断されたとします。スレッド A1 は、限られた数の CPU サイクルで送信操作を完了することが保証されていますか? さらに、各スレッドが 1 つの送信だけを行いたいとします。プログラムが十分に長く実行された場合 (一部のスレッドを枯渇させる可能性があるか、「最悪の瞬間」にスレッドを中断して再開する「悪意のある」スケジューラを使用)、少なくとも 1 つの送信が成功することが保証されますか?

ここでは、典型的なシナリオにはあまり関心がありませんが、最悪の場合の保証には関心があります。障害、ロック、待機のないアルゴリズムの詳細については、ノンブロッキング アルゴリズム (ウィキペディア) を参照してください

4

4 に答える 4

11

通常の送受信は、定義上ブロック操作です。select ステートメントを使用して、ノンブロッキングの送受信を行うことができます。

select {
case ch <- msg:
default:
}

(受信は非常に似ています。case ステートメントを置き換えるだけです。)

送信は、チャネルのバッファに空きがある場合にのみ行われます。それ以外の場合は、デフォルトのケースが実行されます。内部的にミューテックスがまだ使用されていることに注意してください(コードを正しく読んでいる場合)。

于 2011-07-17T20:45:37.297 に答える
4

Go メモリ モデルでは、送受信が非ブロッキングである必要はなく、現在のランタイム 実装sendではとのチャネルがロックされますrecv。これは、たとえば、OS スケジューラが、チャネルのロックを既に取得しているときに、同じチャネルで送信または受信を試みる別の go-routine を実行している別のスレッドに割り込むと、送信または受信の go-routine を枯渇させる可能性があることを意味します。 .

したがって、答えは残念ながらノーです:(

(誰かがノンブロッキング アルゴリズムを使用してランタイムの一部を再実装しない限り)。

于 2012-04-15T23:18:50.883 に答える
1

制限された数のサイクル内で操作が完了することが保証されているかどうかを尋ねていますが、これはもちろん、この言語 (またはほとんどの基になる OS) の設計上の考慮事項ではありません。

シングルスレッドで実行する場合、Go はゴルーチン間で協調的なマルチタスキングを使用します。したがって、1 つのルーチンが決して譲歩しない場合、もう 1 つのルーチンは決して実行されません。プログラムが複数のスレッドで実行される場合 ( で設定GOMAXPROCS)、複数のゴルーチンを同時に実行できます。この場合、OS がスレッド間のスケジューリングを制御します。ただし、どちらの場合も、関数呼び出しの完了までの時間に保証された上限はありません。

ゴルーチンの協調的な性質により、スケジュールの実行をある程度制御できることに注意してください。つまり、ルーチンがプリエンプトされることはありません。譲るまで、スレッドの制御を保持します。

ブロック動作については、言語仕様を参照してください。

容量 (要素数) は、チャネル内のバッファーのサイズを設定します。容量が 0 より大きい場合、チャネルは非同期です。バッファーがいっぱいでない (送信) または空でない (受信) 場合、通信操作はブロックされることなく成功し、要素は送信された順序で受信されます。容量がゼロまたは存在しない場合、送信側と受信側の両方の準備が整った場合にのみ通信が成功します。

チャネルでのノンブロッキング送受信は、select前述の構文を使用して実行できることに注意してください。

于 2011-07-18T17:40:09.353 に答える
0

ゴルーチンは、チャネルまたはそれらに送信される値を所有しません。したがって、チャネルで値を送信した/送信しているゴルーチンの実行ステータスは、チャネルのバッファがいっぱいでない限り、他のゴルーチンがそのチャネルで値を送受信する機能に影響を与えません。チャネルのバッファがいっぱいの場合、すべての送信がブロックされます。対応する受信が発生するまで、またはバッファが空になるまで。この場合、対応する送信があるまですべての受信がブロックされます。

ゴルーチンは協調スケジューリングを使用するため (チャネル操作、システムコール、または への明示的な呼び出しのいずれかを介してスケジューラに譲らなければならないruntime.Gosched())、ゴルーチンが「可能な限り最悪の時間」に中断されることはありません。ゴルーチンが絶対に譲歩しない可能性があります。その場合、スレッドが無期限に拘束される可能性があります。実行スレッドが 1 つしかない場合、他のゴルーチンは決してスケジュールされません。ゴルーチンがまったくスケジュールされない可能性はありますが、統計的にはありそうにありません。ただし、送信または受信時に 1 つを除くすべてのゴルーチンがブロックされている場合は、残りのゴルーチンをスケジュールする必要があります。

デッドロックが発生する可能性があります。2 つのゴルーチンを実行している場合:

func Goroutine(ch1, ch2 chan int) {
   i := <-ch1
   ch2 <- i
}
...
ch1, ch2 := make(chan int), make(chan int)
go Goroutine(ch1, ch2)
go Goroutine(ch2, ch1)

次に、明らかなように、両方のゴルーチンが他方が値を送信するのを待っていますが、これは決して起こりません。

于 2011-07-20T03:37:58.777 に答える