これは、バッファー付きチャネルとバッファーなしチャネルの大きな違いにつながります。バッファーなしチャネルでは、送信側と受信側のゴルーチンが同時にデータを交換することが保証されますが、バッファー付きチャネルにはそのような保証はありません。
バッファなしチャネルに基づいて、限られたストレージ スペースをチャネルに追加して、バッファ付きチャネルを形成します。バッファリングされたチャネルは、送信時に受信者の受信を待たずに送信プロセスを完了することができ、ブロックは発生しません。ブロックはストレージ領域がいっぱいの場合にのみ発生します。同様に、バッファリングされたチャネルにデータがある場合、受信時にブロックされません。チャネルに読み取るデータがなくなるまで、チャネルは再びブロックされます。
バッファリングされていないチャネルにより、送信プロセスと受信プロセスが確実に同期されます。バッファなしの送受信プロセスは、宅配業者があなたに、階下に宅配業者を取りに行くように電話をかけるのと似ています。宅配業者の配達プロセス全体が同期して行われ、あなたと宅配業者はお互いに会うことができます。ただし、その場合、配達員はすべての配達作業を完了する前に、全員が階下に降りて作業が完了するまで待たなければなりません。宅配業者が宅配ボックスに入れて利用者に受け取りを通知すれば、宅配業者と利用者は非同期の送受信処理となり、効率が大幅に向上します。バッファリングされたチャネルは、そのような「エクスプレス キャビネット」です。
バッファリングされたチャネルを作成する
バッファ付きチャネルを作成するにはどうすればよいですか?次のコードを参照してください。
チャネル インスタンス := make(chan チャネル タイプ, バッファ サイズ)
- チャネル タイプ: バッファなしチャネルの使用法と一致し、チャネルによって送受信されるデータのタイプに影響します。
- バッファ サイズ: チャネルが保持できる要素の最大数を決定します。
- チャネル インスタンス: 作成されたチャネル インスタンス。
例を通してバッファリングされたチャネルの使用法を理解しましょう。次のコードを参照してください。
package main
import "fmt"
func main(){
// 3つの要素が含まれるバッファサイズの整数チャネルを作成します。
ch:= make(chan int、3)
//現在のチャネルサイズを確認する
fmt.Println(len(ch))
// 3つの整数要素をチャネルに送信する
ch <-1
ch <-2
ch <-3
//現在のチャネルサイズを確認する
fmt.Println(len(ch))
}
コード出力は次のとおりです。
0
3
コードの説明は次のとおりです。
- 8 行目では、バッファ サイズが 3 要素の整数型のチャネルを作成します。
- 11行目、現在のチャンネルのサイズを確認します。バッファリングされたチャネルの作成時には内部要素は空であるため、len() を使用して取得される戻り値は 0 になります。
- 14 ~ 16 行目では、3 つの整数要素をチャネルに送信します。バッファリングされたチャネルが使用されるためです。受信するゴルーチンがない場合でも、送信者はブロックしません。
- 19行目では3チャンネル埋まっていますので、この時点でチャンネル長は3となります。
ブロッキング状態
バッファ付きチャネルは多くの点でバッファなしチャネルと似ています。バッファなしチャネルは、長さが常に 0 のバッファ付きチャネルと考えることができます。したがって、この機能によれば、バッファリングされたチャネルは次の状況でもブロックされます。
- バッファリングされたチャネルがいっぱいのときにデータを再送信しようとするとブロックされました。
- バッファリングされたチャネルが空のときにデータを受信しようとするとブロックされました。
Go 言語が無制限の長さのチャネルを提供するのではなく、チャネルの長さを制限するのはなぜですか?
チャネルは 2 つのゴルーチン間の通信のブリッジであることがわかっています。ゴルーチンを使用するコードでは、一方がデータを提供し、もう一方がデータを消費する必要があります。データプロバイダーのデータ供給速度がコンシューマーのデータ処理速度よりも速い場合、チャネルの長さが制限されていない場合、アプリケーションがクラッシュするまでメモリは拡張し続けます。したがって、チャネルの長さを制限することは、データプロバイダの供給速度を制限するのに有利であり、供給されるデータ量は、コンシューマの処理能力 + チャネルの長さの範囲内でなければ正常にデータを処理できません。