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. 空の構造の詳細



All Articles