概要
runtime.Gosched() について。
滅多に使うことはないと思いますが、知識としてしっておくと便利かもしれません。
他の言語では yield って名前で用意されていることが多いですね。 (C# とか Java とか)
「実行権の放棄」という日本語で呼ばれることもあります。私は基本 yield って用語をそのままで使うことが多いです。
非同期処理を作っているときにたまに使ったりする。サンプルを見ていただいた方がわかりやすいと思います。
サンプル
package runtimes import ( "fmt" "runtime" "sync" "github.com/devlights/gomy/output" ) // Gosched -- runtime.Gosched() のサンプルです。 // // # REFERENCES // - https://dev.to/abh1navv/12-common-uses-of-java-streams-1pgk // - https://journal.lampetty.net/entry/concurrency-in-go-goroutines func Gosched() error { const ( numGoroutines = 5 ) var ( wg sync.WaitGroup fn = func(wg *sync.WaitGroup, i int, prefix string, enableYield bool) { defer wg.Done() output.Stderrf(prefix, "hello [%d]\n", i) if enableYield { runtime.Gosched() } output.Stderrf(prefix, "world [%d]\n", i) } ) // // runtime.Gosched() は、他の言語での yield に相当する (C#とかJavaとか) // 呼び出すと、他のゴルーチンに処理コンテキストを譲ってもいいよという通知をGoランタイムに教えるイメージ。 // (かならず、コンテキストがスイッチするわけではない) // 「実行権の放棄」とも言ったりする。 // var ( enableYield = false ) // runtime.Gosched() を呼び出さない版 // yield しないので、基本的に処理コンテキストを持っているゴルーチンは // Goランタイムから一時停止などをされない限り、自身の処理を完結させることが出来る。 // 今回のサンプルで実行している関数は、I/O待機などがないので // 出力は各々のゴルーチン毎に出力されていく。 wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { go fn(&wg, i, fmt.Sprintf("[goroutine-%02d]", i), enableYield) } wg.Wait() output.StdoutHr() // runtime.Gosched() を呼び出す版 // yield するように要請するので、それぞれのゴルーチンは // 可能であれば、自身の処理コンテキストを他のゴルーチンに // 譲る挙動をする。なので、ゴルーチンによっては自身の処理を // 1回で完結させることが出来ない場合がある。 // (runtime.Gosched()の呼び出しで他のゴルーチンにコンテキストが移ることがあるため) // なので、出力は 前半部と後半部に別々の時間軸で出力される場合がある。 enableYield = true wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { go fn(&wg, i, fmt.Sprintf("[goroutine-%02d]", i), enableYield) } wg.Wait() return nil }
実行すると例えば以下のようになります。
gitpod /workspace/try-golang (master) $ task task: [run] go run . -onetime ENTER EXAMPLE NAME: sched [Name] "runtime_gosched" [goroutine-04] hello [4] [goroutine-04] world [4] [goroutine-02] hello [2] [goroutine-02] world [2] [goroutine-01] hello [1] [goroutine-01] world [1] [goroutine-03] hello [3] [goroutine-03] world [3] [goroutine-00] hello [0] [goroutine-00] world [0] -------------------------------------------------- [goroutine-04] hello [4] [goroutine-00] hello [0] [goroutine-01] hello [1] [goroutine-02] hello [2] [goroutine-03] hello [3] [goroutine-04] world [4] [goroutine-00] world [0] [goroutine-01] world [1] [goroutine-02] world [2] [goroutine-03] world [3] [Elapsed] 252.06µs
最初の分が、runtime.Gosched() を呼んでいないバージョンです。
次の分が runtime.Gosched() を呼んでいるバージョン。
毎回、必ずこのようになるとは限りません。たまたま、yield することが出来た ゴルーチン がいる場合はこのようになったります。
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。