ホームページ  >  記事  >  バックエンド開発  >  Golangチャンネルの実装について

Golangチャンネルの実装について

藏色散人
藏色散人転載
2021-05-06 10:00:172220ブラウズ

以下は 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 サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。