1 回答
TA贡献1828条经验 获得超3个赞
这已经通过评论得到了回答(请参阅mkopriva的评论),但让我提供一个“答案化”版本。
首先,一个小小的旁白:
done := make(chan interface{})
我通常看到这里。由于从未发送过任何实际值,因此通道的类型并不重要,但是发送空值根本不占用空间,而发送空值则占用空间。1 个make(chan struct{})
struct
interface{}
现在,我们在这里要做的,在结束语中,2是:
等待(或至少假装等待)某个服务器应答;
如果发生超时,请停止等待服务器;和
将我们的ID发送到结果渠道
或者如果频道关闭(表明其他人打败我们做任何事情),不要打扰上述任何一项。done
作为一个复杂因素,我们还将记录我们等待了多长时间,即使我们没有得到答案。
主要功能:
创建通道,其唯一目的是 d,以便从它接收立即返回它们在 EOF 处缺少值的零值;
done
close
剥离这些工人的一些数字(具体为10);
等待第一个交付结果(可能是由于超时,结果而导致的结果缺失)
关闭通道以使其余工作线程终止;和
done
打印最终结果。
我们感兴趣的是为什么闭包的代码是用代码片段编写的:
select { case <-done: case <-time.After(simulatedLoadTime): }
在其中。
这里的诀窍是预先评估其所有替代方案。因此,在开始选择过程之前,它会评估通道,但也调用 。然后,等待具有值或位于通道末端并因此具有EOF的任何一个,以先发生者为准。select
done
time.After()
select
如果还没有戈鲁廷将结果发送回主戈鲁廷,则该通道将不会关闭。此时,所有 goroutines 都将阻塞在通道上。但是所有的戈鲁丁人也会叫.done
done
time.After
该代码启动一个 goroutine,经过一段时间后,它将在通道上发送当前时间。然后,它返回该通道。因此,这两个操作中至少有一个将完成:通道将关闭或 get 关闭,并且由于 EOF,我们将在其上获得零值,或者返回的通道将有一个时间发送到它,我们将收到该值。无论我们实际获得哪个值,我们都会将值放在地板上,但是两个运算符中的一个最终会解除阻塞的事实保证了这个goroutine最终能够继续。time.After
<-
done
time.After
<-
首先发生的事件将是通道的关闭或时间的接收。我们不知道这是哪一个,因为我们不知道通道关闭需要多长时间,但是时间的上限是我们传递给的持续时间有多长。也就是说,要么发生(最终),要么在我们选择的时间之后,部分发生。其中之一肯定会发生。done
done
time.After
done
time.After
现在,如果我们不关心记录我们花费的时间,我们可以把它写成:
select { case <-done: return case <-time.After(simulatedLoadTime): // everything else happens here }
但请注意原始代码中的注释:
// do not want to return on <-done because we still want to log ...
因此,这解释了缺乏.return
超时后,我们现在必须尝试将我们的ID发送到主goroutine。但是,我们可能无法做到这一点:其他一些工作 goroutine 可能会击败我们发送,而主 goroutine 仅从通道读取一个值。为了确保我们不会被困在这里,我们还有另一个.我们将尝试发送我们的 ID,但如果频道现在关闭或关闭,则停止。然后,我们将记录并返回。select
done
1 个我一直认为Go应该有一个预先声明的空结构类型,只是为了方便和风格的东西。我们在这里将其用于我们的频道。我们将它用于仅作为集合而存在的映射,除了它们还将具有预先声明的仅方便和样式类型。但这完全是另一回事。done
阿拉伯数字这里没有特别好的理由使用闭包。未导出的普通函数也可以正常工作。假设我们使用的是闭包,我们可以捕获通道、值和通道,而不是将它们作为参数。我不清楚为什么作者选择把它写成一个可能成为函数的闭包,然后不去打扰闭包给我们带来的任何好东西。done
wg *WaitGroup
result
- 1 回答
- 0 关注
- 83 浏览
添加回答
举报