[Go言語]GoroutineとContextパッケージ

こんにちは。KOKUKIです。

最近、Go言語で並行処理を学んでいます。Go言語にはGoroutineという処理を並行で走らせられる機能がデフォルトでついていて、かなり学びやすいです。

Contextパッケージは、並行処理のキャンセル処理とかにかなり便利そうだったので、学習記録としてここに残しておきます。

WithCancel

最初は、WithCancelを確認してみましょう。

Contextは、子ゴルーチンにメインゴルーチンからの情報を伝搬させることができるようです。

そのため、最初にcontext.Backgroundで空のContextを作って、そのContextで情報のやりとりを行います。

上記の例では、作成したContextをWithCancelメソッドでラップして、戻り値としてcancel関数を受け取っています。

このcancel関数を実行するとContextを渡した子ゴルーチン側で検知ができるようですね。ただし検知するためには、子ゴルーチン側で<-ctx.Done()を実行する必要があります。

こういう場合は、Select文が便利で、caseを使うことでチャネルごとの分岐ができるので、caseの一つに<-ctx.Done()を定義してcancel実行を待ち受けています。

プログラムを実行してみましょう。

6が出力されたところで、プログラムが停止しました。

以下のように<-ctx.Done()をコメントアウトすると無限ループになるので、一度試して見てください。

WithDeadline

次はWithDeadlineを見ていきましょう。

WithDeadlineはその名の通り、制限時間を儲けることができるメソッドです。

deadLine := time.Now().Add(100 * time.Millisecond)」で100ミリセック以内の制限時間を定義しています。

sayHello関数では50ミリセック以内で動作が完了するので、このままプログラムを実行するとHelloが返されます。

続いて、「deadLine := time.Now().Add(10 * time.Millisecond)」に変更したらどうなるでしょうか。

はい。TimeOverのになりましたね。これは結構便利な機能かもしれません。

WithTimeout

WithTimeoutは、コンテキストにタイムアウトを設定します。その名の通りですね。

このサンプルでは、google.comに対してリソースのリクエストを行なっています。

その際に、「ctx, cancel := context.WithTimeout(req.Context(), 10*time.Millisecond)」似て、10ミリ秒以内のタイムアウトを設けました。

つまり、10ミリ秒以内に処理が完了しないとリソースが取得できないことになります。

プログラムを実行してみましょう。

タイムアウトしてくれましたね。

続いて「tx, cancel := context.WithTimeout(req.Context(), 10000*time.Millisecond)」のように10秒にしたらどうなるでしょうか。

今度はちゃんと取れましたね。

指定時間内に処理が終わるか確認したい時なんかに便利そうですね。

WithValue

WithValueも便利そうです。

WithValueは、goroutine間で値の受け渡しを可能にします。

上記のサンプルでは、仮想のデータベース(ローカルキャッシュでもいいです)から任意のKey(userIDKeyType)の情報が存在するかgoroutineを使って判定しています。

データ量が少ないので、有効性を感じないかもしれませんが、ひとまずプログラムを実行してみましょう。

Keyにはselfnoteを渡しています。

trueが返却されましたね。

続いて、keyをhogeに変えてみましょう。

プログラムを実行します。

OKですね。

これは仕事で使うかもしれないので、マスターしておきたいですね。

終わりに

Contextパッケージは面白いですね。プログラムの幅が広がっていく感覚がして楽しいです^^

もっと色々なことができるようになって、世の中にたくさんのサービスを送り出したいですね。

それでは、また!

関連記事

お勧め書籍