如何在两个通道上等待,并在它们都准备好进行读取时继续执行?

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

how to wait on 2 channels and continue when they are both ready for read

问题

假设我有两个缓冲通道,我该如何等待它们,并且只有当两个通道中都至少有一个项目时才继续执行?

这就像组装一个有两个部分的机器,只有当两个部分都准备好时,我才能继续工作。

  • 两个队列都为空,等待。

    | | | | 队列 A


    | | | | 队列 B

  • 队列 A 有一个元素,但队列 B 为空,等待。

    | | | X | 队列 A


    | | | | 队列 B

  • 队列 A 有两个元素,但队列 B 为空,仍然等待。

    | | Y | X | 队列 A


    | | | | 队列 B

  • 两个队列都有项目,从每个队列中消耗一个。

    | | Y | X | 队列 A


    | | | Z | 队列 B

  • 现在,队列 B 再次为空,等待...

    | | | Y | 队列 A


    | | | | 队列 B

英文:

Suppose I have 2 buffered channels, How can I wait for both of them, and only continue when both of the channel have at least one item in it?

It looks like assemble a machine with two parts, only when both part are at hand can I continue my work.

Both queue are empty, wait.
-------------------
|     |     |     |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------


Queue A has one element but Queue B empty, wait
-------------------
|     |     |  X  |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------


Queue A has two elements but Queue B empty, still wait
-------------------
|     |  Y  |  X  |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------


Both queue has item in it, consume one from each queue.
-------------------
|     |  Y  |  X  |   QUEUE A
-------------------

-------------------
|     |     |  Z  |   QUEUE B
-------------------


Now, Queue B empty again, wait ...
-------------------
|     |     |  Y  |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------

答案1

得分: 2

从2个通道接收不是原子操作。您可以使用内置的len()函数检查通道缓冲区中排队的元素数量,但无法进行2个通道的原子接收。

这意味着当您从一个通道接收一个值时,另一个通道可能还没有准备好接收(例如,另一个goroutine可能已经从它接收了)。

如果只有一个goroutine消耗和处理这些值,只需从两个通道接收一个值,如果值尚未准备好(如果通道尚未准备好接收),它将阻塞:

v1 := <- ch1
v2 := <- ch2

// 处理 v1 和 v2

还请注意,如果通道已关闭,接收操作也会成功。

英文:

Receiving from 2 channels is not atomic. You can check the number of elements queued in a channel's buffer using the builtin len() function, but you can't do a 2-channel atomic receive.

Meaning by the time you receive a value from one channel, the other channel might not be ready to receive from (e.g. another goroutine might already have received from it).

If there is only one goroutine that consumes and processes these values, simply receive a value from both channels, it will block if a value is not ready (if channel is not ready to receive from):

v1 := &lt;- ch1
v2 := &lt;- ch2

// process v1 and v2

Also note that receiving also succeeds if the channel is closed.

答案2

得分: 0

如何这样:

type Foo1 struct {}
type Foo2 struct {}

type Combination struct {
	foo1 *Foo1
	foo2 *Foo2
}

func mergeChan(chIn chan *Foo1, chIn2 chan *Foo2, chOut chan *Combination) {
	for foo1 := range chIn {
		chOut <- &Combination{
			foo1: foo1,
			foo2: <-chIn2,
		}
	}
}

监听 chOut,你将始终从两个通道接收到组合数据。

英文:

How about something like this:

type Foo1 struct {}
type Foo2 struct {}

type Combination struct {
	foo1 *Foo1
	foo2 *Foo2
}

func mergeChan(chIn chan *Foo1, chIn2 chan *Foo2, chOut chan *Combination) {
	for foo1 := range chIn {
		chOut &lt;- &amp;Combination{
			foo1: foo1,
			foo2: &lt;-chIn2,
		}
	}
}

Listening to chOut you would always receive combinations from both channels.

huangapple
  • 本文由 发表于 2017年7月12日 23:13:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/45061595.html
匿名

发表评论

匿名网友

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

确定