2017-08-01 5 views
0

私は非常に新しいです。なぜこのコードにこの出力があるのか​​わかりません。私はスリープによって新しいゴルーチンに指定された時間だけ別のスレッドが開始されることを理解しています。私は逐次的に論理を描こうとしています。そして、 "世界"のように見えるのはいつも "hello"の前に印刷するべきです。Goroutineはforループで相互交換可能なアクションを引き起こします

package main 

import (
    "fmt" 
    "time" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     time.Sleep(1 * time.Millisecond) 
     fmt.Println(s, i) 
    } 
} 

func main() { 
    go say("world") 
    say("hello") 
} 

実際の出力:

world 0 
hello 0 
hello 1 
world 1 
world 2 
hello 2 
hello 3 
world 3 
world 4 
hello 4 

予想される出力:

world 0 
hello 0 
world 1 
hello 1 
world 2 
hello 2 

...など

+6

ゴルーチンは異なるゴルーチンを注文するものについて何ら保証を提供しませんどのコード行を実行するかを指定します。 – captncraig

答えて

0

私は睡眠が新しいゴルーチンが他方を開始させることを理解指定された時間のスレッド

これは部分的に間違っています。

これは、一度に1つのスレッドしか実行できないコアが1つのマシンでは正しいでしょう。

複数のコアを搭載したマシンでは、コアと同じ数のゴルーチンを実行できます。並列に実行されるゴルーチンでは、前後に何が実行されるかはまったく保証されません。

0

並行操作が「常に」実行される順序を確実にすることはできません。これが並行処理の仕組みです。実行順序を制御する場合は、同時に実行しないでください。また、同期構成(たとえば、mutex、チャネル)を使用して操作の順序を制御することもできます。

0

他の人からも言われているように、実行の順序については保証するものではありません。

Goスケジューラにはプロセッサの割り当て方法を決定する内部アルゴリズムがあり、同期に頼らずにこれを制御することはほとんどできません(これは正しい方法です)。

あなたは、タスク間の同期を制御する方法を学ぶことに興味を持っている場合は、syncパッケージで、またどのようにchannels作品を見てみましょう:

https://golang.org/pkg/sync/

https://tour.golang.org/concurrency/2

にしかし、私はしたいです他の人が言及していないことを追加してください。実行順序を制御することはできませんが、質問の性質上、コメントする価値があります。

スケジューラのヒントに使用できるruntime.Gosched関数があります。それによってプロセッサが生成され、他のスレッドが実行される可能性が高くなります。

https://golang.org/pkg/runtime/#Gosched

あなたの代わりに睡眠のGoschedに呼び出しを追加した場合、私のテストでは、それははるかに可能性があること、「こんにちは」と「世界」でしょう出力再びかかわらず、保証はありません(ために、彼ら時々ランダムな順序で表示されます)。

このようにそれを試してみてください。

package main 

import (
    "fmt" 
    "runtime" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     fmt.Println(s, i) 
     runtime.Gosched() 
    } 
} 

func main() { 
    go say("world") 
    say("hello") 
} 

最後に、あなたにも興味を持つ可能性があります。この記事を見てみましょう:

http://container-solutions.com/surprise-golang-thread-scheduling/

関連する問題