Go、非同期相互作用の練習

チャネル、メインプロセスでの実装、ブロック操作を別のgoroutineで行う方法について少し説明します。



チャネルとヌル値


チャネルは、非同期開発のためのツールです。 ただし、多くの場合、チャネルで何を転送するかは重要ではありません。転送の事実のみが重要です。 時々見つかる
完了:= make chan bool
/// [...]
完了< -true

boolのサイズはプラットフォームによって異なります。はい、通常、サイズについて心配する必要がある場合はそうではありません。 しかし、まだ何も送信しない、または何も送信しない方法があります(さらに正確には、空の構造について話している)。
done := make chan struct { }
// [...]
完了< -struct { } { }

それだけです。

片道チャンネル


もう1つ明確に強調したい点があります。 例:
func main {
done := make chan struct { }
go func {
//もの
done < -struct { } { } //完了前に通知する
}
< -done //ゴルーチンの完了を待機
}

それは簡単です- ゴルーチンで 行われるの記録のためだけに必要です。 原則として、 ゴルーチンではそれを読み取ることができます( 完了チャネルから値を取得します)。 トラブルを避けるために、コードが混乱している場合、パラメーターが役立ちます。 goroutineに渡される関数のパラメーター。 今そう
func main {
done := make chan struct { }
go func done chan < -struct { } {
//もの
done < -struct { } { } //完了前に通知する
} 完了
< -done //ゴルーチンの完了を待機
}
これで、このようなチャネルを送信すると、書き込み専用チャネルに変換されます。 ただし、以下では、チャネルは双方向のままです。 原則として、チャネルは引数を渡さずに一方向に変換できます。
done := make chan struct { }
writingChan := chan < -struct { } done //最初の括弧は重要ではありません
readingChan := <- chan struct { } done //最初の括弧が必要です
頻繁に必要に応じて、これらすべてを行う関数を作成できます。 これがplay.golang.orgの例です 。 これにより、コンパイル段階でいくつかのエラーをキャッチできます。

メインOSスレッドでの実行


たとえば、OpenGL、libSDL、Cocoaなどのライブラリは、プロセスデータ構造にスレッドローカルストレージを使用します。 つまり、メインOSスレッドで実行する必要があります。それ以外の場合はエラーになります。 runtime.LockOSThread()関数を使用すると、現在のゴルーチンをOSの現在のスレッドに固定できます。 初期化中に( init関数で)呼び出すと、これがメインOSスレッド(メインOSスレッド)になります。 同時に、他のゴルーチンは並列OSスレッドで静かに実行できます。

別のスレッドで計算を行うには(この場合は、別のOSスレッドにあるという事実ではなく、ゴルーチンについて話します)、関数をメインのスレッドに単純に転送するだけで十分です。 以上です。
シーツ
play.golang.orgで
パッケージ メイン

インポート
「fmt」
「ランタイム」


func init {
ランタイム。 LockOSThread //現在のゴルーチンを現在のスレッドに固定する
}

func main {
/ *
コミュニケーション
* /
done := make chan struct { } // <-停止して終了
stuff := make chan func // <-メインスレッドに関数を送信

/ *
2番目のスレッドを作成します(この場合、2番目のゴルーチンですが、問題ではありません)
そして、最初に「ジョブ」の送信を開始します
* /
go func done chan < -struct { } 、stuff chan < -func { //並列操作
stuff < -func { //最初に行った
fmt。 Println "1"
}
stuff < -func { // 2番目の
fmt。 Println "2"
}
stuff < -func { // 3番目に行った
fmt。 Println "3"
}
完了< -struct { } { }
} 完了、スタッフ
ループ
{
{を選択
case do := < -stuff //「作業」を取得
do //および実行
ケース <-完了
ブレークループ
}
}
}



ブロッキング操作の削除


IO操作のブロックはより一般的ですが、同様に無効にされます。
シーツ
play.golang.orgで
パッケージ メイン

「os」を インポート

func main {
/ *
コミュニケーション
* /
stop := make chan struct { } //「書き込み」ゴルーチンを停止するために必要
done := make chan struct { } //完了するのを待つ
write := make chan [ ] byte //書き込み用データ

/ *
IO操作用の並列スレッド
* /
go func write < -chan [ ] byte 、stop < -chan struct { } 、done chan < -struct { } {
ループ
{
{を選択
case msg := < -write //書き込みメッセージを受信
os。 標準出力書き込み msg //非同期書き込み
ケース <-停止
ブレークループ
}
}
完了< -struct { } { }
} 書き込み、停止、完了
write <- [ ] byte "Hello" //メッセージを送信
write <- [ ] byte "World! \ n " //書き込み
停止< -struct { } { } //停止
< -done //完了を待つ
}

複数のゴルーチンが1人の「ライター」にメッセージを送信した場合でも、ブロックされます。 この場合、バッファのあるチャネルが役立ちます。 スライスが参照タイプである場合、ポインターのみがチャネルを介して送信されます。




参照先



  1. LockOSThreadの説明
  2. blog.golang.orgの空の構造
  3. 空の構造の詳細

Source: https://habr.com/ru/post/J267785/


All Articles