🦁

Go、並行処理の権化Goroutineを利用する時に良いものを調べてみた

2023/06/03に公開

Go並行処理についてまとめ

Goの歴史

Goはプログラミング言語の1つである。Googleにおいて2009年ロバート・グリースマ、ロブ・パイク、ケン・トンプソンによって設計された。
Goは、静的型付け、C言語の伝統に則ったコンパイル言語、メモリ安全性、ガベージコレクション、構造的型付け(英語版)、CSPスタイルの並行性などの特徴を持つ。
Goのコンパイラ、 ツール、およびソースコードは、すべてフリーかつオープンソースである。
https://ja.wikipedia.org/wiki/Go_(プログラミング言語)

マスコット

Gopher(ホリネズミ)がマスコットキャラクターとして採用されている。
goher.png

設計者はC++が好きじゃないらしい

後のインタビューで、3人の言語設計者すべてが、新しい言語を設計する主なモチベーションとしてC++が好きでないこと(英語版)を共有していたことを述べている。
こういうのはちょっとおもろい。

並行処理について触る前にその強さを図るものを用意

runtime/traceパッケージというカスタマイズのしやすいものがある。

使い方

サンプルコード
https://github.com/eiei114/gorutine-sample/blob/main/app/runtime_trace.go

f, err := os.Create("trace.out")でtrace.outというファイルを作成する。このファイルにトレース情報が書き込まれる。

err = trace.Start(f)
	if err != nil {
		panic(err)
	}
	defer trace.Stop()

/// 以下からトレースしたい処理をかく

実行方法

go tool trace trace.out

実行結果

以下の画像のようなものが出てくる
アドレスをクリックすると自前のブラウザで詳細な結果が見られる。
trace.png

UIもなかなかよきかな

goroutineをやってみよう

goroutineとは

goroutineは、Goのランタイムによって管理される軽量なスレッドである。
goroutineは、通常の関数呼び出しと同じように見えるが、実際には別のスレッドで並行して実行される。

色々と調べてみた。
僕のPCにあるCPUは4コア8スレッドである。
一コアでにスレッドの処理が行うことが可能である。
spec.png
goroutineでは各スレッドに処理を自動で振り分けることができる。
つまりこのPCでは同時に8個の処理を行うことが可能である。

goroutineの使い方

関数の前にgoをつけるだけでgoroutineとして実行される。

func main() {
	go Yay("Yay!")
	go Yay("Yoy!")

	// これがないとgoroutineが終わる前にmainが終わってしまう
	fmt.Scanln()
}

func Yay(say string) {
	fmt.Println(say)
}

実行結果

今回の実行結果は以下のようになる。
複数回実行すると順番が変わることがある。
これはgoroutineの実行順が不定であることによる。

Yoy!
Yay!

Contextを使ってみよう

Contextとは

ざっと調べてみた感じでは以下のようなものだと思った。

  • 処理のタイムアウト伝達
  • 処理のキャンセル伝達
  • リクエストの値の伝達

goroutineを利用する時にcontextを利用するとタイムアウト、キャンセル

Contextの使い方

WithTimeoutを利用することで引数からタイムアウトの設定ができる。
context.Background()を利用することでコンテキストを作成することができる。

func main() {
	// コンテキストの作成。このコンテキストは3秒後にキャンセルされる
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel() // main関数が終わる前にキャンセルを呼び出す

	// このgoroutineはコンテキストがキャンセルされるまで実行し続ける
	go func() {
		for {
			select {
			case <-time.After(1 * time.Second):
				fmt.Println("動いているよ")
			case <-ctx.Done():
				fmt.Println("終わったよ...")
				return
			}
		}
	}()

	// ここでは5秒待つ
	time.Sleep(5 * time.Second)
}

実行結果

3秒間は動いているが動き続けるように設定している。

動いているよ
動いているよ
終わったよ...

コンテキストはgoroutineを利用する上で確実に欲しいパッケージだと感じた。
contextを一個宣言しそれにエラーやキャンセル処理を返せばそのcontextを
利用するgoroutineはすべてキャンセルされるのはコンパクトで良いと感じた。

まとめ

以上までがとりあえず今後goroutineを触っていく上で重要な事柄になってくると思われる。
まだ初歩中の初歩なので次章からはそれぞれについてふかぼって行きたいと感じた。

Discussion