Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

对于 channel 容量的一些疑问 #22

Closed
haozibi opened this issue Jul 1, 2019 · 2 comments
Closed

对于 channel 容量的一些疑问 #22

haozibi opened this issue Jul 1, 2019 · 2 comments
Labels
question Further information is requested

Comments

@haozibi
Copy link
Contributor

haozibi commented Jul 1, 2019

你好,我在看书的时候,对其中 channel 容量的有些疑问,所以想问一下我的理解哪里有问题,谢谢

  • 第一处

<a class="anchor" id="first-response-wins-3"></a>
<h4>第三种“采用最快回应”的实现方式</h4>
<div>
如果一个“采用最快回应”用例中的数据源的数量很少,比如两个或三个,我们可以让每个数据源使用一个单独的缓冲通道来回应数据,然后使用一个<code>select</code>代码块来同时接收这三个通道。
示例代码如下:
<pre class="line-numbers"><code class="language-go">package main
import (
"fmt"
"math/rand"
"time"
)
func source() <-chan int32 {
c := make(chan int32, 1) // 必须为一个缓冲通道
go func() {
ra, rb := rand.Int31(), rand.Intn(3)+1
time.Sleep(time.Duration(rb) * time.Second)
c <- ra
}()
return c
}
func main() {
rand.Seed(time.Now().UnixNano())
var rnd int32
// 阻塞在此直到某个数据源率先回应。
select{
case rnd = <-source():
case rnd = <-source():
case rnd = <-source():
}
fmt.Println(rnd)
}
</code></pre>

func source() <-chan int32 {
	c := make(chan int32, 1) // 必须为一个缓冲通道
	go func() {
		ra, rb := rand.Int31(), rand.Intn(3)+1
		time.Sleep(time.Duration(rb) * time.Second)
		c <- ra
	}()
	return c
}

不知道为什么必须为 1,即使为 0 也完全正常

  • 第二处

<h4>定时器(ticker)</h4>
<div>
我们可以使用尝试发送操作来实现一个每隔一定时间发送一个信号的定时器。
<pre class="line-numbers"><code class="language-go">package main
import "fmt"
import "time"
func Tick(d time.Duration) <-chan struct{} {
c := make(chan struct{}, 1) // 容量必须严格为1
go func() {
for {
time.Sleep(d)
select {
case c <- struct{}{}:
default:
}
}
}()
return c
}
func main() {
t := time.Now()
for range Tick(time.Second) {
fmt.Println(time.Since(t))
}
}
</code></pre>

c := make(chan struct{}, 1) // 容量必须严格为1

此处的容量为什么严格为1,容量为 0 没有问题呀?

上面两处的容量为 0 都可以正常运行,而且不存在 “数据请求者因为种种原因未及时准备好接收,则所有回应者的尝试发送都将失败,从而所有回应的数据都将被错过。”

@dotaheor
Copy link
Contributor

dotaheor commented Jul 1, 2019

对于第一个,如果不为缓冲通道的话,则两个未被选择的case对应的协程将处于永久阻塞状态,造成内存泄露。

对于第二个,缓冲为0的情况其实也可以,具体取决于具体应用的要求。缓冲为0时,(站在接收者的角度),每两个连续接收操作的间隔肯定大于d;而缓冲为1时,(站在发送者的角度),尽量保证在每个Nd时刻发送一个信号。其实缓冲大于1也不是一点道理没有,但是容易造成瞬时发生很多接受操作的情况。

这里缓冲取1是为了和标准库包中的time.Tick函数的行为保持一致。

不过一些描述确实需要再调整一下。多谢提出这个问题。

@TapirLiu TapirLiu added the question Further information is requested label Jul 1, 2019
@haozibi
Copy link
Contributor Author

haozibi commented Jul 1, 2019

@TapirLiu 非常感谢解答,而且我注意到线上图书已经更新了,辛苦了。

@haozibi haozibi closed this as completed Jul 1, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants