2017-08-01 92 views
0

我很新,我不確定爲什麼這個代碼有這個輸出。我知道睡眠會導致新的goroutine在指定的時間內啓動另一個線程。我試圖按順序繪製出邏輯,看起來「世界」應該總是在「你好」之前打印出來。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

據我所知,睡眠會導致新夠程啓動其他線程指定的時間量

這是部分錯誤!

這對於只有一個內核的機器來說是正確的,一次只能執行一個線程。

在具有多個內核的機器上,可以執行與內核一樣多的並行執行。在並行執行的例程中,根本沒有保證,什麼會在之前或之後執行。

0

你不能肯定地說什麼順序併發操作將「總是」執行英寸這就是併發的工作原理。如果要控制執行順序,則不要同時執行,要麼使用同步構造(例如互斥鎖,通道)來控制操作的順序。

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/