以下は golang のチュートリアル コラムで、Golang チャネルの実装を紹介します。
1. はじめに
チャネルとは、Go 言語が言語レベルで提供するゴルーチン間の通信方法であり、複数のゴルーチン間でメッセージを渡すために使用できます。チャネルはプロセス内通信メソッドであるため、チャネルを介してオブジェクトを渡すプロセスは、関数呼び出し時のパラメータ受け渡し動作とより一貫性があります。たとえば、ポインタも渡すことができます。クロスプロセス通信が必要な場合は、Socket や HTTP などの通信プロトコルを使用するなど、分散システムを使用して問題を解決することをお勧めします。
チャネルは型に関連しています。つまり、チャネルは 1 つの型の値のみを渡すことができ、チャネルを宣言するときにこの型を指定する必要があります。なお、チャネル自体も Go 言語のネイティブ型であり、map などの型と同じステータスであるため、チャネル自体を定義した後にチャネルを通過することもできます。
2. 基礎となる実装
2.1 hchan 構造
type hchan struct {
qcount uint // 队列中当前数据的个数
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // 数据缓冲区,存放数据的环形数组
elemsize uint16 // channel中数据类型的大小(单个元素的大小)
closed uint32 // 表示channel是否关闭标识位
elemtype *_type // 队列中的元素类型
sendx uint // 当前发送元素的索引
recvx uint // 当前接收元素的索引
recvq waitq // 接受等待队列,由recv行为(也就是<-ch)阻塞在channel上的goroutine队列
sendq waitq // 发送等待队列, 由send行为(也就是ch<-)阻塞在channel上的goroutine队列
//lock保护chann中的所有字段,以及在此通道上阻塞的sudoG中的几个字段。
//保持此锁时不要更改另一个G状态(特别是没准备好G),因为这可能会因堆栈收缩而死锁
lock mutex
}
//发送及接收队列的·1结构体
type waitq struct {
first *sudog
last *sudog
}
-
qcount uint //現在のキューに残っている要素の数。
-
dataqsiz uint // リングキューの長さ、つまりバッファのサイズ、つまり make(chan T, N), N。
-
buf unsafe.Pointer // リングキューポインタ。
-
elemsize uint16 // 各要素のサイズ。
-
closed uint32 // 現在のチャネルが閉じているかどうかを示します。チャネルが作成されると、このフィールドはチャネルが開いていることを意味する 0 に設定されますが、close を呼び出してこのフィールドを 1 に設定すると、チャネルが閉じられます。
-
elemtype *_type // データ転送時の割り当てに使用される要素タイプ。
-
sendx uint および recvx uint はリング バッファのステータス フィールドで、バッファの現在のインデックスを示します。送受信できる配列をサポートしています。データ 。
-
recvq waitq // メッセージの読み取りを待機している Goroutine キュー。
-
sendq waitq // メッセージの書き込みを待機している Goroutine キュー。
-
lock mutex // ミューテックス ロック。送信と受信は相互に排他的な操作である必要があるため、読み取りおよび書き込み操作ごとにチャネルをロックします。
#2.2 作成手順
2.2.1 書き込み操作
1. バッファ付きチャネルの作成
#2. チャネルへのデータの書き込み
3.3 書き込みプロセスは次のとおりです。
パイプライン構造全体をロックします。
- 書き込みを確認し、キューからの goroutine を待ってから、要素を goroutine に直接書き込みます。
- recvq が空の場合は、バッファが使用可能かどうかを判断します。利用可能な場合は、現在のゴルーチンからバッファにデータをコピーします。
- バッファがいっぱいの場合、書き込まれる要素は現在実行中の goroutine 構造に保存され、現在の goroutine は sendq のキューに入れられ、実行が一時停止されます。
- 書き込みが完了し、ロックが解除されます。
- #2.2.2 読み取りプロセス
# #Read最初にチャネルグローバルロックを実行します。
sendq を実行して、待機キューから待機中の goroutine を取得してみます。 - 待機中のゴルーチンとバッファがある場合(バッファがいっぱいの場合)、バッファキューの先頭からデータを取り出し、sendqからゴルーチンを取り出します。 goroutine 内のデータを buf アライメントに格納し、読み取りを終了してロックを解放します。
- 待機中のゴルーチンがなく、バッファにデータがある場合は、バッファのデータを直接読み取り、読み取りロックの解除について説明します。
- 待機中の goroutine がなく、バッファがない、またはバッファ領域が空の場合は、現在の goroutine を denq キューに追加し、sleep に入り、 goroutine を書き込んで復帰するのを待ちます。ロックの解除を完了します。
-
-
以上がGolangチャンネルの実装についての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。