teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

追記

2020/10/05 11:55

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -2,4 +2,71 @@
2
2
  スタックはLIFO(後入先出)と呼ばれる挙動です。
3
3
 
4
4
  ただし、質問にあるコードの場合、順番が入れ替わってもおかしくないかもしれません。
5
- (順番が維持される保証のない記述なので)
5
+ (順番が維持される保証のない記述なので)
6
+
7
+ ### 追記
8
+
9
+ 以下のコードを何度も手元で実行した出力を下に貼ります。
10
+ [https://play.golang.org/p/udCf_zvmaF3](https://play.golang.org/p/udCf_zvmaF3)
11
+ ```go
12
+ package main
13
+
14
+ import "fmt"
15
+
16
+ func hey(n int, c chan int) {
17
+ fmt.Println("hey:", n)
18
+ c <- n
19
+ }
20
+ func main() {
21
+ c := make(chan int)
22
+ fmt.Println("setup")
23
+ go hey(1, c)
24
+ go hey(2, c)
25
+ go hey(3, c)
26
+ fmt.Println("started")
27
+ x, y, z := <-c, <-c, <-c // receive from c
28
+
29
+ fmt.Println(x, y, z, x+y+z)
30
+ }
31
+ ```
32
+
33
+ 出力結果
34
+ ```shell
35
+ $ go run .
36
+ setup
37
+ started
38
+ hey: 3
39
+ hey: 2
40
+ hey: 1
41
+ 3 2 1 6
42
+ $ go run .
43
+ setup
44
+ started
45
+ hey: 3
46
+ hey: 1
47
+ hey: 2
48
+ 3 1 2 6
49
+
50
+ ```
51
+
52
+ goステートメントが3行を通り抜けてからhey関数が呼ばれることがわかります。
53
+ そして、このように実行のたびに実行される順番が異なっていることが確認できます。
54
+ つまり、goroutineの準備が完了した状態で次にgoroutineスイッチが起こる時
55
+ 待機しているgoroutine群のどれが起動するのかは不定つまりランダムです。
56
+
57
+ このような挙動はある種狙って組み込まれています。
58
+
59
+ 複数のgoroutineがあるチャネルからの取り出しを待っている状態で一つだけ値をそのチャネルに書き込んだ場合、
60
+ どのチャネルの取り出し待ちが発火するかはランダムです。
61
+
62
+ ランダムにする理由は仕事をするgoroutineを分散させるという狙いがあります。
63
+ (特定のgoroutineだけ働いている状態を回避する)
64
+
65
+ ```go
66
+ x, y, z := <-c, <-c, <-c
67
+ ```
68
+ ここは最初xだけがチャネルからの取り出し待ちになります。
69
+ xが値を受け取ったらyがチャネルからの取り出し待ちになります。
70
+ yが値を受け取ったら最後にzがチャネルからの取り出し待ちになります。
71
+ ここはシーケンシャルに処理されることは保証されるということです。
72
+ (3行に分けて書いても同様です)