2022/06/12

[golang] chan で待つ

オライリーさんからGo言語の本が出たので悩み中。

O’Reilly Japan - 実用 Go言語
https://www.oreilly.co.jp/books/9784873119694/

まだプログラミング言語Goも読み進めていないので早すぎるという気もするが、お仕事で使っている以上実用の本もほしいのが正直なところだ。
まあ、そのうち買うんだろうね。


さて、本題。

処理Aがあって、その処理の後に処理Bを行いたいことがあった。
それだけなら続けて書けば良いだけだったのだが、コンテキストが同じ状態で処理Aと処理Bを実行できないようで(自分で作ってない処理なのでよくわからん)、処理A は goroutine してやらないと処理Bが必ず失敗していた。
つまり、処理Aが非同期になったのだ。

今は処理Aが終わりそうな時間だけtime.Sleep()で待ってから処理Bを実行させているのだが、そういえば非同期処理の待ち合わせがあったなあ、と思い出した。
channelだ。
まあ、goroutine と channel はプログラミング言語Goでも同じ章で説明してあるくらいだしセットで覚えるものよね。

チャネルでの待ち合わせ

チャネルはmake()で作り、close()で閉じられる。使わなければよいだけなのだろうけど、明示的に「これ以降は使えない」というフラグを立ててくれるそうだ。

make(chan 型)で作るが、型は戻り値と思っておけばよさそうだ。
TypeScriptでいえばPromise<型>みたいな感じかな。
単に待ち合わせたいだけだったら戻り値はいらないのだが、そういうときはstruct {}を使えばよいようだ。golangにvoidはないのだね。

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Printf("start\n")
	done := make(chan struct{})
	go func() {
		fmt.Printf("goroutine start\n")
		time.Sleep(10 * time.Second)
		fmt.Printf("goroutine done\n")
		done <- struct{}{}
	}()
	<-done
	fmt.Printf("done\n")
}

実行。

$ go run .
start
goroutine start
goroutine done
done

10秒開けているのだけど、終わってからdoneが実行されている。