Golang: 无法在通道上发送数据

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

Golang: cannot send on channel

问题

为什么它没有在通道上发送信号并阻塞执行?我该如何使这个组合工作,以便我可以向MoneyDive()发送信号并继续执行?

package main

import (
	"fmt"
)

type Quack func(ch chan bool)

type DagobertDuck struct {
	quack Quack
}

func (self *DagobertDuck) MoneyDive() {
	ch := make(chan bool)
	self.quack(ch)
	b := <-ch
	if b {
		fmt.Println("true")
	} else {
		fmt.Println("false")
	}
}

func mockQuack(ch chan bool) {
	fmt.Println("mockQuack start")
	ch <- true
	fmt.Println("mockQuack done")
}

func main() {
	dd := DagobertDuck{quack: mockQuack}
	dd.MoneyDive()
}

链接:https://play.golang.org/p/1omlb7u6-A

英文:

Why is it not sending on the channel and blocking the execution? How can I make this constellation work so that I can send a signal into MoneyDive() and continue execution?

package main

import (
	&quot;fmt&quot;
)

type Quack func(ch chan bool)

type DagobertDuck struct {
	quack Quack
}

func (self *DagobertDuck) MoneyDive() {
	ch := make(chan bool)
	self.quack(ch)
	b := &lt;-ch
	if b {
		fmt.Println(&quot;true&quot;)
	} else {
		fmt.Println(&quot;false&quot;)
	}
}

func mockQuack(ch chan bool) {
	fmt.Println(&quot;mockQuack start&quot;)
	ch &lt;- true
	fmt.Println(&quot;mockQuack done&quot;)
}

func main() {
	dd := DagobertDuck{quack: mockQuack}
	dd.MoneyDive()
}

https://play.golang.org/p/1omlb7u6-A

答案1

得分: 8

因为你有一个非缓冲通道,只有在有另一个准备好接收的goroutine时,才能在非缓冲通道上发送值而不阻塞。

由于你只有一个goroutine,它被阻塞了。解决方法很简单:在一个新的goroutine中启动Quack.quack()方法:

go self.quack(ch)

然后输出结果(在Go Playground上尝试):

mockQuack start
mockQuack done
true

另一个选项是不启动新的goroutine,而是创建一个带有缓冲区的通道,这样它可以在没有准备好接收的接收器的情况下保存一些值:

ch := make(chan bool, 1) // 带有缓冲区的通道,缓冲区大小为1

这样就创建了一个通道,它可以在没有准备好接收的接收器的情况下“存储”一个值。除非首先从通道接收到该值(或者准备好接收该值的接收器),否则对通道的第二次发送也会被阻塞。

Go Playground上尝试这个带缓冲区的通道版本。

规范中的相关部分:发送语句:

> 在通信开始之前,通道和值表达式都会被求值。**如果接收器准备好接收,发送可以进行,非缓冲通道上的发送可以进行。**如果缓冲通道有空间,发送可以进行。关闭的通道上的发送会导致运行时恐慌。在_nil_通道上的发送会永远阻塞。

注意:

根据接收到的值,你打印truefalse。这可以用一行代码完成,不需要if语句:

fmt.Println(b)

你甚至可以摆脱b局部变量,直接打印接收到的值:

fmt.Println(&lt;-ch)

另外,我假设你使用通道是因为你想玩一下,但在你的情况下,mockQuack()可以简单地返回bool值,而不使用通道。

英文:

Because you have an unbuffered channel, and you can only send a value on an unbuffered channel without blocking if there is another goroutine which is ready to receive from it.

Since you only have 1 goroutine, it gets blocked. Solution is simple: launch your Quack.quack() method in a new goroutine:

go self.quack(ch)

Then the output (try it on the Go Playground):

mockQuack start
mockQuack done
true

Another option is to not launch a new goroutine but make a buffered channel, so it can hold some values without any receivers ready to receive from it:

ch := make(chan bool, 1) // buffered channel, buffer for 1 value

This creates a channel which is capable of "storing" one value without any receivers ready to receive it. A second send on the channel would also block, unless the value is received from it first (or a receiver ready to receive a value from it).

Try this buffered channel version on the Go Playground.

Relevant section from the spec: Send statements:

> Both the channel and the value expression are evaluated before communication begins. Communication blocks until the send can proceed. A send on an unbuffered channel can proceed if a receiver is ready. A send on a buffered channel can proceed if there is room in the buffer. A send on a closed channel proceeds by causing a run-time panic. A send on a nil channel blocks forever.

Notes:

Based on the received value you print true or false. This can be done with a single line, without the if statement:

fmt.Println(b)

You can even get rid of the b local variable, and print the received value right away:

fmt.Println(&lt;-ch)

Also I assume you used channels because you wanted to play with them, but in your case mockQuack() could simply return the bool value, without the use of channels.

huangapple
  • 本文由 发表于 2016年5月24日 15:23:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/37406914.html
匿名

发表评论

匿名网友

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

确定