簡體   English   中英

golang緩沖通道意外結果

[英]golang buffer channel unexpected result

package main
import (
    "time"
    "runtime"
)

var c = make(chan int, 2)

func main() {
  go worker(1)
  for i := 0; i < 30; i++ {
    go func() {
            // k := i   make a local copy not make any difference
            c <- i
    }()
  }
  time.Sleep(100* time.Second)
}

func worker(id int) {
  for {
    a := <-c
    println(a, runtime.NumGoroutine())
    time.Sleep(time.Second)
  }
}

輸出是不可預測的,有時如下所示。

7 9
13 29
13 28
13 27
13 26
13 25
13 24
13 23
16 22
16 21
17 20
19 19
21 18
21 17
23 16
25 15
26 14
26 13
26 12
26 11
26 10
26 9
26 8
26 7
27 6
27 5
13 4
28 3
30 2
30 2

我知道發送方將在緩沖區通道已滿時阻止,並且當通道可用時發送方可以繼續。

  1. 為什么輸出不是恆定輸出0-29? 怎么做?
  2. 如何在goroutine中存儲變量/局部變量?
  3. 如果許多發件人被阻止,它們是否按FIFO順序喚醒?

輸出不是恆定的,因為不同的goroutine共享相同的局部變量i。 如果取消注釋行並將其移動到goruoutine調用之前,則會看到恆定輸出0-29。 更好的方法是將i變量移至goroutine函數參數。

規格中未指定喚醒順序。 您應該將其視為隨機的。

3是FIFO

1因為在for循環內創建的goroutine不一定按順序執行。 基礎的Go調度程序將隨機啟動一個(這是通道分配其值的方式)。 的,當然,所有的人都會生成,但他們(被安排)在點開始time.Sleep(...)main被稱為(去調度是合作之一,像函數調用某些點這樣做,頻道操作等-例如this

2直接使用頻道:

var (
    c  = make(chan int, 2)
    wg = &sync.WaitGroup{}
)

func main() {
    wg.Add(1)
    go worker(1)

    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 30; i++ {
            c <- i
        }
        close(c)
    }()
    wg.Wait()
}

func worker(id int) {
    defer wg.Done()
    for a := range c {
        println(a, runtime.NumGoroutine())
        time.Sleep(time.Second)
    }
}

關於傳遞for循環變量; 您幾乎正確地完成了操作。 您只需要在goroutine之外添加以下代碼以創建本地閉包:

var (
    wg = &sync.WaitGroup{}
)

func main() {
    for i := 0; i < 3; i++ {
        localClosure := i // <- this line

        wg.Add(1)
        go func() {
            defer wg.Done()
            println(localClosure)
        }()
    }

    wg.Wait()
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM