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