我很难理解电子书的并发性。我希望有人可以一步一步地与我分手,这样我就能清楚地了解最新情况。
这是主要方法:
func main(){
c := make(chan int)
go printer(c)
wg.Add(1)
// Send 10 integers on the channel.
for i := 1; i <= 10; i++ {
c <- i
}
close(c)
wg.Wait()
}
这是打印机方法:
func printer(ch chan int) {
for i := range ch {
fmt.Printf("Received %d ", i)
}
wg.Done()
}
以下是我的问题:
wg.Add(1)
作为一个组来执行,而不是wg.Add(1)
main method for loop
我做过一些研究,似乎没有人能够以简单的方式向我解释。
对于sending integers on channel
和adding to wait groups
的任何一步一步的简单说明将不胜感激。
更新
sourcecode =&gt; https://github.com/goinaction/code/blob/master/chapter1/channels/hellochannels.go
答案 0 :(得分:0)
除非您故意在主线程中添加阻塞点,否则程序将在接收方打印最后一项之前抓住执行。
这是WaitGroup
对象和WaitGroup.Wait()
调用完成的工作。
通过这个,您告诉主线程另一个操作同时发生,并且您希望在结束程序执行之前等待它完成。这将通过wg.Done()
声明发出信号。
然而,在这种情况下,这只是需要,否则接收器将无法在主线程执行结束之前接收最后一个项目。 但是在大多数情况下,通道也是同步抽象,它们决定了程序执行的流程。
但首先, WaitGroup
未在循环中添加的原因,是因为您的程序中只有一个您必须等待的点。单个goroutine,由单个通道组成。
由于在该示例中,我们正在使用Unbuffered
频道,因此它一次只允许通过频道传输1条消息。
这意味着对于发送器发送的每条消息,发送方将被阻塞,直到接收方检索到此类消息并从通道中删除。
当发送器发送最后一个项目时,它将关闭指示接收器的通道,以后将不再接收更多消息。
使用range ch
进行的迭代将在收到“10”后终止,并且goroutine
的执行最终会中断循环执行。
这就是发生的事情:
// Transmitter 发送“1”
由于频道为unbuffered
,// 发射器现已被屏蔽。
// Receiver 收到“1”
// Receiver 现在被阻止,直到某些内容传输到频道。
//发射器现在已解锁,可以再次发射。
// .....
// Transmitter 发送“10”
// Receiver 收到“10”
在此之后,go函数最终可以通过调用它的静态方法WaitGroup
来减去Done
上的计数器,并且计数器将达到零,这意味着块操作由wg.Wait()
发生。 1}}将抓住存在,主线程最终可以完成并终止程序执行。
关键点:
channel
频道的unbuffered
,一次意味着1条消息。另一方面,使用缓冲通道,在接收器实际决定获取它们之前,您可以同时传输多条消息,并且WaitGroup
的优势可能变得更加明显。<- i
,您正在向channel
发送内容,而range ch
则会检索此类消息。传输的消息是固定变量类型,在这种情况下是整数。 答案 1 :(得分:-1)
编者注:第一段是对作者的原始代码的回应,该代码已被编辑为具有与最初呈现的代码明显不同的语义。
您提供的代码示例就证明WaitGroup
的用法而言并不是一个特别好的示例,因为程序在主方法结束时终止,而不是由任何协调处理WaitGroup
。您可以删除对wg.Done()
的调用,该程序仍然可以编译并执行正常。
但我很乐意回答您更常见的问题。
为什么我们只将wg.Add(1)作为一个组来执行,而不是在主循环方法中使用wg.Add(1)?
听起来你问为什么我们不为for循环中的每个整数增加wg
。这不是WaitGroups
的重点。一个典型的用例是为每个goroutine添加1,我们正在协调超出主要的goroutine。在此示例中,还有一个goroutine(处理printer
的goroutine,因此我们只向WaitGroup
添加1。
上述示例的更多 clear 版本将如下所示:
var wg sync.WaitGroup
func printer(ch chan int) {
for i := range ch {
fmt.Printf("Received %d ", i)
}
wg.Done()
}
func sender(ch chan int) {
for i := 0; i <= 10; i++ {
ch <- i
}
close(ch)
}
func main() {
c := make(chan int)
go printer(c)
go sender(c)
wg.Add(1)
fmt.Println("Waiting...")
wg.Wait()
fmt.Println("Finished")
}
在这个例子中,我们希望等待 printer
方法完全打印掉我们继续使用主goroutine的所有数字。所以我们告诉我们的主要goroutine到Wait()
,直到所有整数都被打印出来,此时我们告诉主线程继续。与您的示例不同,我们在将所有内容输入其中后close
频道,这允许printer
函数停止range
上的阻止并继续调用{{} 1}} - 在原始示例中,wg.Done
永远不会阻止printer
上的阻止,因此永远不会实际调用range
我真的不理解频道,期间。
希望上面的例子让事情更清楚一点?我担心这部分问题对我来说有点过于宽泛。