没有等待组,将数据从不同的go例程写入相同的chanel可以正常工作

时间:2019-03-11 14:07:44

标签: go

在等待wg.Wait()之后,使用带有waitgroup的多个go例程将数据写入同一通道时,出现异常,表明所有go例程处于睡眠状态或解除锁定。

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var wg sync.WaitGroup

func CreateMultipleRoutines() {
    ch := make(chan int)

    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        wg.Add(1)
        go func() {
            for j := 0; j < 10; j++ {
                ch <- j
            }
            wg.Done() // indication of go routine is done to main routine
        }()
    }

    fmt.Println(runtime.NumGoroutine())
    wg.Wait()           //wait for all go routines to complete
    close(ch)           // closing channel after completion of wait fo go routines
    for v := range ch { // range can be used since channel is closed
        fmt.Println(v)
    }
    fmt.Println("About to exit program ...")
}

当试图在没有等待组的情况下实现此操作时,我可以通过循环将数据推送到通道的确切次数来从通道读取数据,但是我无法调整范围,因为当我们关闭通道时会出现恐慌。这是示例代码

package main

import (
    "fmt"
    "runtime"
)

func main() {
    ch := make(chan int)


    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        go func(i int) {
            for j := 0; j < 10; j++ {
                ch <- j * i
            }
        }(i)
    }

    fmt.Println(runtime.NumGoroutine())

    for v := 0; v < 100; v++ {
        fmt.Println(<-ch)
    }
    fmt.Println("About to exit program ...")
}

我想了解为什么即使所有go例程都发出Done()信号,处于等待状态的waitgroup为何仍在等待,这反过来使go例程的数量为零

2 个答案:

答案 0 :(得分:2)

我认为您的原始代码存在一些问题。

  1. 您要先关闭频道,然后再阅读。
  2. 由于您的频道只有1个“大小”,因此无法获得使用10个goroutine的优势。因此,一个goroutine一次可以产生一个结果。

我的解决方案是产生一个新的goroutine来监视10个goroutine是否完成了工作。在那里,您将使用自己的<script type="text/javascript"> const el = document.getElementsByClassName('scrollable')[0] const settouch = (e) => el.style.webkitOverflowScrolling = 'touch' el.addEventListener("touchend", settouch, false); </script>

然后代码如下:

WaitGroup

答案 1 :(得分:1)

默认情况下,chan 不保存任何项目,因此所有go例程在发送时都会被阻止,直到从中读取某些内容为止。他们实际上从未到达wg.Done()语句。

一种解决方案是在自己的go例程中关闭通道。将您的wg.Wait()close(ch)行换成这样:

go func() {
    wg.Wait() //wait for all go routines to complete
    close(ch) // closing channel after completion of wait fo go routines
}()

然后,您可以在通道上进行选择,该通道仅在所有发送go例程完成后(隐式接收到所有值)才会关闭。