两个例程在同一个通道上进行通信

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

Two routines communicating on the same channel

问题

我有一个函数,给定一个切片和一个数组,它会逐个将切片的元素发送到通道中。

Playground链接

package main

import (
	"fmt"
)

var list1 = []string{"1", "2", "4"}

var list2 = []string{"11", "22", "44"}

func throw(ch chan string, list []string) {
	for _, el := range list {
		fmt.Println("Thrown ", el)
		ch <- el

	}
	close(ch)
	return
}

func main() {
	c := make(chan string)
	go throw(c, list1)
	go throw(c, list2)
	for i := range c {
		fmt.Println("received ", i)
	}
}

在某个时刻,通道被关闭,但其中一个函数仍然需要向其发送数据。我应该如何处理这种情况?在这里,创建两个单独的通道似乎是最合理的选择,但我希望两个数据都通过同一个通道传递。

英文:

I have a function that, given a slice and an array, will send the elements of the slice to the channel one by one

Link to playground

package main

import (
	&quot;fmt&quot;
)

var list1 = []string{&quot;1&quot;, &quot;2&quot;, &quot;4&quot;}

var list2 = []string{&quot;11&quot;, &quot;22&quot;, &quot;44&quot;}

func throw(ch chan string, list []string) {
	for _, el := range list {
		fmt.Println(&quot;Thrown &quot;, el)
		ch &lt;- el

	}
	close(ch)
	return
}

func main() {
	c := make(chan string)
	go throw(c, list1)
	go throw(c, list2)
	for i := range c {
		fmt.Println(&quot;received &quot;, i)
	}
}

At some point the channel get closed, but one of the functions still needs to send data to it. How should I handle this? Making to separate channel seems the most reasonable choice here, but I want both data to pass through the same channel.

答案1

得分: 4

Go语言要求发送方的代码知道通道是否已关闭。因此,像你的代码片段那样,每个goroutine都可以随意关闭通道,这是有问题的。

一种解决方案是使用sync.WaitGroup来协调每个goroutine何时完成,并让第三个goroutine执行关闭操作。所以你需要修改throw函数的代码,如下所示:

func throw(ch chan string, list []string, wg *sync.WaitGroup) {
    defer wg.Done()
    // 函数的当前主体,不包括close()调用
}

然后将生成goroutine的代码更改为以下内容:

var wg sync.WaitGroup
wg.Add(2)
go throw(c, list1, &wg)
go throw(c, list2, &wg)
go func() {
    wg.Wait()
    close(c)
}()

这样,在另外两个goroutine完成后,通道才会被关闭。你可以在这里尝试修改后的示例:http://play.golang.org/p/nUiwjGglgU

英文:

Go expects the code on the sending side of the channel to know whether the channel has been closed or not. So code like your snippet where each goroutine can close the channel without regard for the other is buggy.

One solution is to use a sync.WaitGroup to coordinate when each goroutine has completed, and have a third goroutine perform the close. So you'd modify your throw function to look something like:

func throw(ch chan string, list []string, wg *sync.WaitGroup) {
    defer wg.Done()
    // current body of function, without the close() call
}

And change the code that spawns the goroutines to the following:

var wg sync.WaitGroup
wg.Add(2)
go throw(c, list1, &amp;wg)
go throw(c, list2, &amp;wg)
go func() {
    wg.Wait()
    close(c)
}()

This way your channel will only be closed after the other two goroutines complete. You can experiment with this modified version of your example here: http://play.golang.org/p/nUiwjGglgU

huangapple
  • 本文由 发表于 2014年8月28日 10:30:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/25539807.html
匿名

发表评论

匿名网友

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

确定