pythonのasyncioでは、TaskGroupを用いて、実行タスクのCancel
が可能なのですが、goroutineの場合、どのようにキャンセルを伝播すれば良いのか明確にわからなかった為、調べました。のメモ。
pythonのTaskGroupの実行タスクのCancelについては以下を参照ください。
まずは上記Python公式に記載のあるコードを例に、キャンセル伝播をしないverを、goroutineで記述したいと思います。
package main import ( "fmt" "sync" "time" ) func job(taskId int, sleepTime int) { fmt.Printf("Task %d: start\n", taskId) time.Sleep(time.Duration(sleepTime) * time.Second) fmt.Printf("Task %d: done\n", taskId) } func main() { var wg sync.WaitGroup for i := 1; i < 3; i++ { wg.Add(1) go func() { defer wg.Done() job(i, i) }() } wg.Wait() }
上記実行すると以下出力になりまする。
Task 2: start Task 1: start Task 1: done Task 2: done
2始まりな部分は正直疑問(1からだと思った...)なのですが、一旦置いておきます。終わりはsleepする時間差で1,2の順番になっていますね。
goroutineのキャンセル伝播なのですが、調べてみると、goroutine間での値の共有や、goroutineの管理をするにはContext
を用いるようです。
Contextは公式から
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes
とあるように、デッドライン
・キャンセル信号
・リクエストスコープの値
を伝播するようです。
また、公式DocにContextを用いる際の注意点も記載があるため、一読することをお勧めします。
では、Contextを用いてキャンセルの伝播を行うコードに変更していきます。
今回は1.5秒を目途にキャンセルを行います。そのためそれ以降の処理はdoneではなく、cancelと表示するようにします。
package main import ( "context" "fmt" "sync" "time" ) func job(ctx context.Context, taskId int, sleepTime int) { fmt.Printf("Task %d: start\n", taskId) select { case <-time.After(time.Duration(sleepTime) * time.Second): fmt.Printf("Task %d: done\n", taskId) case <-ctx.Done(): fmt.Printf("Task %d: cancel\n", taskId) } } func main() { var wg sync.WaitGroup ctx, cancel := context.WithCancel(context.Background()) defer cancel() for i := 1; i < 4; i++ { wg.Add(1) go func() { defer wg.Done() job(ctx, i, i) }() } time.Sleep(1500 * time.Millisecond) cancel() wg.Wait() }
キャンセルがわかりやすいように、goroutineの数を一つ増やしました。
実行した結果がこちら
Task 1: start Task 3: start Task 2: start Task 1: done Task 3: cancel Task 2: cancel
良いですね。キャンセル信号が正常に伝播され、1.5秒以降のタスクはCancel扱いとなっている為、意図した挙動になっています。
今回はgoroutineに対してのキャンセル伝播はどのように行うのかを調べました。
Contextはキャンセル伝播だけでなく、デッドライン・リクエストスコープの値の伝播とまだまだ奥は深そうなので、時間があるときにもう少し遊んでみたいなぁというお気持ち。