Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 循环检查并发程序中的条件_Go_Concurrency_Goroutine - Fatal编程技术网

Go 循环检查并发程序中的条件

Go 循环检查并发程序中的条件,go,concurrency,goroutine,Go,Concurrency,Goroutine,我正在读一本关于Go中并发性的书我现在正在学习它,我发现了以下代码: c:=sync.NewCond&sync.Mutex{} 队列:=生成[]接口{},0,10 removeFromQueue:=funcdelay time.Duration{ 时间,睡眠延迟 c、 L.锁 队列=队列[1:] fmt.println已从队列中删除 c、 L.解锁c.信号 } 对于i:=0;i

我正在读一本关于Go中并发性的书我现在正在学习它,我发现了以下代码:

c:=sync.NewCond&sync.Mutex{} 队列:=生成[]接口{},0,10 removeFromQueue:=funcdelay time.Duration{ 时间,睡眠延迟 c、 L.锁 队列=队列[1:] fmt.println已从队列中删除 c、 L.解锁c.信号 } 对于i:=0;i<10;i++{ c、 L.锁 //为什么是这个循环? 对于lenqueue==2{ c、 等等 } fmt.println添加到队列 queue=appendqueue,结构{}{} 从队列中移除1*time.Second c、 L.解锁 }
问题是,我不理解作者为什么引入由注释标记的for循环。据我所知,如果没有它,程序是正确的,但是作者说循环存在,因为Cond只会发出发生了一些事情的信号,但这并不意味着状态确实发生了变化


在什么情况下这是可能的?

如果手头没有真正的书,而只是一些似乎脱离上下文的代码片段,很难说出作者的具体想法。但我们可以猜测。在大多数语言(包括Go)中,关于条件变量有一个普遍的观点:等待某个条件得到满足通常需要一个循环。在某些特定情况下,不需要循环

我认为Go文档更清楚地说明了这一点。特别是,sync的文本说明中说:

Wait以原子方式解锁c.L并暂停调用goroutine的执行。稍后恢复执行后,等待在返回前锁定c.L。与其他系统不同,等待不能返回,除非被广播或信号唤醒

因为等待第一次恢复时c.L没有被锁定,所以调用方通常不能假设等待返回时条件为true。相反,调用方应该在循环中等待:

c.L.Lock()
for !condition() {
    c.Wait()
}
... make use of condition ...
c.L.Unlock()
我在解释循环原因的短语中添加了粗体强调

是否可以省略循环取决于多个因素:

在什么情况下,另一个goroutine调用信号和/或广播? 有多少个goroutine正在运行,它们并行运行时可能在做什么? 正如Go文档所说,有一种情况我们在Go中不必担心,我们可能会在其他一些系统中担心。在某些系统中,当条件变量上没有实际调用信号或其等价物时,有时通过信号等价物恢复等待等价物

您引用的队列示例特别奇怪,因为只有一个goroutine可以向队列添加条目,该goroutine运行计数为10的for循环。其余的goroutine仅删除条目。因此,如果队列长度为2,我们暂停并等待队列长度已更改的信号,那么队列长度只能更改为1或0:没有其他goroutine可以添加到它,只有我们在此时创建的两个goroutine可以从中删除。这意味着给定这个特定的例子,我们有一种情况,在这种情况下,循环毕竟是不需要的

同样奇怪的是,队列的初始容量是10,这是我们将要放入的项目的数量,然后我们在其长度正好为2时开始等待,因此无论如何我们都不应该达到该容量。如果我们要剥离可能会添加到队列中的其他goroutine,那么当lenqueue==2时等待的循环确实可以通过删除来发出信号,该删除将计数从2降至1,但在插入之前没有机会恢复,从而将计数推回到2。但是,根据具体情况,在其他两个goroutine分别添加一个条目之前,可能无法恢复该循环,例如,将计数推到3。那么,当长度正好为2时,为什么要重复循环呢?如果想法是保留队列插槽,我们应该在计数大于或等于2时循环


除此之外,初始容量与此无关,因为如有必要,队列将动态调整为一个较大的片段。

这是哪本书?如果没有它,程序将是正确的。程序什么也不做,因此它不可能是正确的。我认为代码是用来显示信号和等待是如何协同工作的。这段代码只是信号和等待的一个例子,其余的代码用来展示这些函数是如何工作的。没有它们,代码的其余部分不会工作;它的存在只是为了允许信号并等待出现。您确定for循环的代码没有在书中单独的goroutine中执行吗?@kostix该代码的复制与书中显示的完全相同。@marco.m由Katherine Cox Buday编写的Go中的并发性。