技術共有

Go 言語 --- 同時プログラミング チャネル (デュアル チャネル、シングル チャネル) とアプリケーション例 (プロデューサー コンシューマー、プリンター モデル)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

チャネル

ゴルーチンは同じアドレス空間で実行されるため、共有メモリへのアクセスは同期する必要があります。ゴルーチンはメモリを共有するのではなく、通信を通じてメモリを共有します。

参照型チャネルは CSP モードの特定の実装であり、複数の goroutine 通信に使用されます。内部的に同期を実装して同時実行の安全性を確保します。

チャンネルタイプ

マップと同様に、チャネルも make によって作成された基礎となるデータ構造への参照です。
チャネルをコピーするか、関数パラメータの受け渡しにチャネルを使用する場合、チャネル参照をコピーするだけなので、呼び出し元と呼び出し先は同じチャネル オブジェクトを参照します。他の参照型と同様に、チャネルのゼロ値は nil です。
チャネルを定義するときは、チャネルに送信される値のタイプも定義する必要があります。 チャネルは、組み込みの make() 関数を使用して作成できます。

make (chan Type)
make (chan Type,capacity)
  • 1
  • 2
  • 容量 = 0 の場合、チャネルはバッファリングされず、読み取りと書き込みがブロックされます。容量 > 0 の場合、チャネルにはキャッシュがあり、容量要素がいっぱいになるまで書き込みはブロックされません。
  • チャネルは演算子 <- を介してデータを送受信します。データの送受信の構文は次のとおりです。
channel<-value   //发送value 到channel
<-channel     //接收并将其丢弃
x:=<-channel   //从 channel 中接收数据,并賦偵给x
x,ok:=<-channel   //功能同上,同时检查通道是否已关闭或者是否为空
  • 1
  • 2
  • 3
  • 4

デフォルトでは、相手側の準備ができていない限り、データの送受信時にチャネルがブロックされるため、明示的なロックを必要とせずに goroutine の同期が簡単になります。

成し遂げる

ここに画像の説明を挿入します

  • パイプはプリントの前に 1 つとプリントの後ろに 1 つ配置されます。
  • Person2 が最初に実行され、パイプラインにデータがない場合、ブロックされます。
  • Person1 が実行され、データを印刷した後、そのデータをパイプに入力すると、Person2 がそれを感知して印刷を開始します。

チャネルを介した同期とデータ対話の実装

ここに画像の説明を挿入します
ここに画像の説明を挿入します

バッファリングされていないチャネル

バッファなしチャネルは、受信前に値を保存する機能がないチャネルです。
このタイプのチャネルでは、送信ゴルーチンと受信ゴルーチンが同時に送信操作と受信操作を完了する準備ができている必要があります。 2 つのゴルーチンが同時に準備ができていない場合、チャネルにより、最初に送信または受信操作を実行するゴルーチンがブロックされて待機します。
チャネルへの送信と受信のこの対話は本質的に同期的です。 1 つの操作が他の操作から独立して存在することはできません。
次の図は、バッファなしチャネルを使用して 2 つのゴルーチンがどのように値を共有できるかを示しています。
ここに画像の説明を挿入します

  • つまり、チャンネル自体に物を入れておけばすぐに取り出すことができます。
  • ステップ 1 では、両方のゴルーチンがチャネルに到着しますが、どちらも送信または受信を開始しません。
  • ステップ 2 では、左側のゴルーチンがチャネルに手を伸ばし、チャネルにデータを送信する動作をシミュレートします。このとき、ゴルーチンは交換が完了するまでチャネルにロックされます。
  • ステップ 3 では、右側のゴルーチンがチャネルに手を入れ、チャネルからのデータの受信をシミュレートします。このゴルーチンも、交換が完了するまでチャネル内にロックされます。
  • ステップ 4 と 5 で交換が発生し、最後にステップ 6 で両方のゴルーチンがチャネルから手を離します。これにより、ロックされたゴルーチンが解放されることがシミュレートされます。どちらのゴルーチンも他のことを実行できるようになりました。

バッファーなしのチャネルを作成する

make (chan Type)//等价于make (chan Type,0)
  • 1

バッファ サイズが指定されていない場合、チャネルは同期であるため、送信側の送信準備が整い、受信側の受信準備が整うまでブロックされます。

ここに画像の説明を挿入します

  • ch&lt;-i はデータをチャネルに書き込みます。このとき、サブコルーチンもブロックされ、パイプがデータを読み取った後、続行されます。
  • ただし、println はパイプが読み取られた後にデータを印刷するため、印刷速度はシステムによって決まります。

バッファリングされたチャネル

バッファリングされたチャネルは、受信前に 1 つ以上の値を保存できるチャネルです。
このタイプのチャネルでは、ゴルーチンが送信と受信を同時に完了する必要はありません。チャネルには、送受信アクションをブロックするさまざまな条件もあります。受信アクションは、受信するチャネルに値がない場合にのみブロックされます。送信アクションは、送信される値を収容できる使用可能なバッファーがチャネルにない場合にのみブロックされます。
これは、バッファー付きチャネルとバッファーなしチャネルの間に大きな違いをもたらします。バッファーなしチャネルでは、ゴルーチンの送信と受信が同時にデータを交換することが保証されますが、バッファー付きチャネルにはそのような保証はありません。
ここに画像の説明を挿入します

  • ステップ 1 では、右側のゴルーチンがチャネルから値を受信して​​います。
  • ステップ 2 では、右側のゴルーチンが値を受信するアクションを独立して完了し、左側のゴルーチンがチャネルに新しい値を送信しています。
  • ステップ 3 では、左側のゴルーチンはまだチャネルに新しい値を送信しており、右側のゴルーチンはチャネルから別の値を受信して​​います。このステップの 2 つの操作は同期したり、相互にブロックしたりすることはありません。
  • 最後に、ステップ 4 で、すべての送受信が完了します。チャネルにはまだいくつかの値があり、さらに値を保存するためのスペースがいくつかあります。

作成する

make (chan Type,capacity)
  • 1

バッファ容量が指定されている場合、チャネルは非同期になります。バッファにデータ送信用の未使用スペースがあるか、受信可能なデータが含まれている限り、通信はブロックされずに続行されます。

成し遂げる

ここに画像の説明を挿入します

  • 十分な数が格納されている場合、メイン コルーチンがデータを読み取って空き領域がある場合、サブ コルーチンは実行を継続し、その後の印刷順序は不確かになります。
    ここに画像の説明を挿入します

チャンネルを閉じる

チャネルは ok を使用して、チャネルがまだ開いているかどうかを検出できます。チャネルが閉じている場合、データは読み取られません。

ここに画像の説明を挿入します

  • num ,ok:=<-chチャネルが閉じているかどうかを検出できます。

知らせ

  • チャネルは、ファイルほど頻繁に閉じる必要はありません。本当に送信するデータがない場合、または範囲ループなどを明示的に終了したい場合にのみチャネルを閉じてください。
  • チャネルを閉じると、それ以上データをチャネルに送信できなくなります (パニック エラーがトリガーされ、受信がすぐにゼロ値を返します)。
  • チャネルを閉じた後も、引き続きチャネルからデータを受信できます。
  • nil チャネルの場合、送信と受信の両方がブロックされます。
    ここに画像の説明を挿入します
  • レンジを使用してチャネルを横断し、自動的にループから抜け出すことができます。
    ここに画像の説明を挿入します

一方向チャネル

デフォルトでは、チャネルはデュアル質問です。つまり、チャネルにデータを送信したり、チャネルからデータを受信したりできます。
ただし、チャネルがパラメータとして渡されることがよくあり、その値はデータの送信のみまたはデータの受信のみに一方向で使用されることが期待されます。このとき、チャネルの方向を指定できます。一方向チャメル変数の宣言は、次のように非常に簡単です。

var ch1 chan int //ch1双向
var ch2 chan<-float64 //ch2单向,只能用于写float64数据
var ch3 <-chan int  //ch3单向,只能用于读int数据
  • 1
  • 2
  • 3

chan&lt;- は、データがパイプに入り、データがパイプに書き込まれ、呼び出し元に出力されることを意味します。
&lt;-chan は、データがパイプから取得されることを示します。呼び出し側にとっては、パイプからのデータが取得されます。これはもちろん入力です。
チャネルは暗黙的に受信のみまたは送信のみの一方向キューに変換できますが、一方向チャネルを通常のチャネルに変換することはできません。

ここに画像の説明を挿入します

単一チャネルを利用して生産者/消費者モデルを実装する

ここに画像の説明を挿入します