如何退出频道范围/收集结果

huangapple go评论86阅读模式
英文:

How to exit a channel range / collect results

问题

我需要同时处理几个任务,然后“收集”结果。以下是我想出的代码,但我想知道这是否是正确的方法(即惯用法/最佳实践),或者是否有我可能忽略的问题。

package main

import "fmt"
import "sync"

func main() {
    // ch 是 int 类型的提供者。容量是 99,但实际上应该是 3
    ch := make(chan int, 99)
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            ch <- i
        }(i)
    }
    wg.Wait()
    for v := range ch {
        fmt.Println("consume ", v)
        if len(ch) == 0 {
            close(ch)
        }
    }
    fmt.Printf("All done")
}

请注意,这段代码使用了 goroutine 和 channel 来实现并发任务处理和结果收集。首先,它创建了一个带有 99 个缓冲区的 int 类型的 channel。然后,使用 sync.WaitGroup 来跟踪 goroutine 的完成情况。在循环中,它启动了 3 个 goroutine,每个 goroutine 将一个值发送到 channel 中。然后,使用 range 循环从 channel 中接收值,并打印出来。最后,当 channel 中没有值时,关闭 channel,并打印出 "All done"。这段代码的实现方式是合理的,并且符合 Go 语言的惯用法和最佳实践。

英文:

I need to process several tasks concurrently and then "collect" the results. Below is the code I came up with but I'm wondering if it's the right way to do this(i.e idiomatic/ best practice) or if there is something wrong that I might miss.

package main

import &quot;fmt&quot;
import &quot;sync&quot;

func main() {
    // ch is the int provider. Cap is 99 but it should 
    // really be 3
	ch := make(chan int, 99)
	var wg sync.WaitGroup
	for i := 0; i &lt; 3; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			ch &lt;- i
		}(i)
	}
	wg.Wait()
	for v := range ch {
		fmt.Println(&quot;consume &quot;, v)
		if len(ch) == 0 {
			close(ch)
		}
	}
	fmt.Printf(&quot;All done&quot;)
}

答案1

得分: 1

这是要翻译的内容:

那样做没有问题,它可以工作。然而,关闭通道的工作应该由生产者来完成,而不是消费者。

为此,我建议将整个生产者过程移入一个 goroutine,并让它等待,然后关闭通道:

package main

import "fmt"
import "sync"

func main() {
    ch := make(chan int, 3)
    var wg sync.WaitGroup

    go func() {
        for i := 0; i < 3; i++ {
            wg.Add(1)
            go func(i int) {
                defer wg.Done()
                ch <- i
            }(i)
        }
        wg.Wait()
        close(ch) // 生产者现在关闭通道
    }()

    // 消费者的唯一责任是迭代通道
    for v := range ch {
        fmt.Println("consume ", v)
    }
    fmt.Printf("All done")
}

[ Go Playground 上查看](http://play.golang.org/p/wT_YjPMtEF)
英文:

There's nothing wrong with that .. it works. However, it really should be the producers job to close the channel (not the consumer).

To that end .. I would propose that you move the entire producer process into a goroutine and have that wait .. then close the channel:

package main

import &quot;fmt&quot;
import &quot;sync&quot;

func main() {
    ch := make(chan int, 3)
    var wg sync.WaitGroup

    go func() {
	    for i := 0; i &lt; 3; i++ {
		    wg.Add(1)
		    go func(i int) {
			    defer wg.Done()
			    ch &lt;- i
		    }(i)
	    }
	    wg.Wait()
	    close(ch) // producer is now closing the channel
    }()

    // Consumer has the single responsibility of iterating over the channel
    for v := range ch {
	    fmt.Println(&quot;consume &quot;, v)
    }
    fmt.Printf(&quot;All done&quot;)
}

<kbd>See it in the Go Playground</kbd>

答案2

得分: 1

我确定你的例子是人为构造的,但是你的例子可以简化得多:

ch := make(chan int, 99)
for i := 0; i < 3; i++ {
    go func(i int) {
        ch <- i
    }(i)
}
for i := 0; i < 3; i++ {
    v := <- ch
    fmt.Println("consume ", v)
}
fmt.Println("All done")

你的真实代码可能更复杂,可能需要类似于 waitGroup 的东西,如果是这种情况,请尽力解释你的具体问题。

在范围内关闭通道以退出范围似乎不符合 Go 的惯用法。

Go Play

英文:

I am sure your example is contrived, but your example could be made much simpler:

ch := make(chan int, 99)
for i := 0; i &lt; 3; i++ {
    go func(i int) {
        ch &lt;- i
    }(i)
}
for i := 0; i &lt; 3; i++ {
    v := &lt;- ch
    fmt.Println(&quot;consume &quot;, v)
}
fmt.Println(&quot;All done&quot;)

Your real code may be more complex and require something like a waitGroup, and if that is the case please do whatever you can to explain your specific problem.

Closing a channel within a range in order to exit the range seems like non-idiomatic Go.

<kbd>Go Play</kbd>

huangapple
  • 本文由 发表于 2015年3月23日 06:28:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/29200625.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定