【问题标题】:Goroutines: Where to closeGoroutines:在哪里关闭
【发布时间】:2020-06-04 13:18:04
【问题描述】:

我不知道应该在哪里关闭我的频道。

这段代码大约需要0.7秒:

options := [3]string{"0", "1", "2"}
str := fmt.Sprintf("%6d ", id)
for j := 0; j < 40000; j++ {
    str += options[rand.Intn(3)]
}
str += "\n"

添加一个io.Writestring对时间没有影响,所以问题出在这个位。

我想要大约 100,000 条这样的记录,所以我想放入一个 goroutine。

func main() {
    file, _ := os.Create("myfile.txt")
    ch := make(chan string)
    for i := 0; i < 100000; i++ {
       go generate(i, ch)
    }

    counter := 0
    for result := range ch {
       counter++
       io.WriteString(file, result)
       if counter == 100000 {
           close(ch)
       }
    }
    file.Close()
}

func generate(id int, c chan string) {
    options := [3]string{"0", "1", "2"}
    str := fmt.Sprintf("%6d ", id)
    for j := 0; j < 40000; j++ {
        str += options[rand.Intn(3)]
    }
    str += "\n"
    c <- str
}

据我了解,我正在关闭接收方的通道,这不理想吗?此外,这样所有 100,000 应该首先发送到 goroutines,然后我才能收到任何。我可以发送请求以生成记录并同时开始接收吗?

【问题讨论】:

  • 您应该在发送方关闭,此时发送方将不再发送任何值。您可以同时发送和接收(在不同的 goroutine 中)。您也可以在从缓冲通道接收到所有值之前关闭,缓冲值仍将被接收。请参阅Tour of Go
  • 如果有多个发送者(如这里),请使用sync.WaitGroup 和一个单独的 goroutine,在 WaitGroup 完成时关闭通道。
  • 解决方案有帮助吗?

标签: go concurrency goroutine


【解决方案1】:

使用计数器关闭您的频道不是一个好习惯。您可以使用sync.WaitGroup。这使您可以更好地控制何时关闭您的频道:

func main() {

    var wg sync.WaitGroup

    ch := make(chan string)
    file, _ := os.Create("myfile.txt")

    for i := 0; i < 100000; i++ {
        wg.Add(1)

        go func(i int) {
            defer wg.Done()

            options := [3]string{"0", "1", "2"}
            str := fmt.Sprintf("%6d ", i)
            for j := 0; j < 40000; j++ {
                str += options[rand.Intn(3)]
            }
            str += "\n"
            ch <- str
        }(i)
    }

    go func() {
        wg.Wait()
        close(ch)
    }()

    for result := range ch {
        io.WriteString(file, result)
    }
    file.Close()
}

【讨论】:

    【解决方案2】:

    看看这是否能解决你的问题..

    func main() {
        file, _ := os.Create("myfile.txt")
        ch := make(chan string)
        wg := new(sync.WaitGroup)
        for i := 0; i < 100000; i++ {
           wg.Add(1)
           go generate(i, ch)
        }
    
        go func(){wg.Wait();close(ch)}()
    
        counter := 0
        for result := range ch {
           counter++
           io.WriteString(file, result)
    
        }
        file.Close()
    }
    
    func generate(id int, c chan string) {
        options := [3]string{"0", "1", "2"}
        str := fmt.Sprintf("%6d ", id)
        for j := 0; j < 40000; j++ {
            str += options[rand.Intn(3)]
        }
        str += "\n"
        c <- str
        wg.Done()
    }
    

    【讨论】:

    • 感谢您的详细回复!我不确定我是否理解正确:我在go func() {wg.Wait()...} 之前放置了一个打印语句。似乎只有在所有 100000 都发送到 go generate() 之后才完成打印?
    猜你喜欢
    • 2011-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 2015-09-26
    • 2013-02-21
    • 2011-03-06
    相关资源
    最近更新 更多