无法理解电子书

时间:2018-06-03 15:26:51

标签: go concurrency

我很难理解电子书的并发性。我希望有人可以一步一步地与我分手,这样我就能清楚地了解最新情况。

这是主要方法:

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 channeladding to wait groups的任何一步一步的简单说明将不胜感激。

更新

sourcecode =&gt; https://github.com/goinaction/code/blob/master/chapter1/channels/hellochannels.go

2 个答案:

答案 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

我真的不理解频道,期间。

希望上面的例子让事情更清楚一点?我担心这部分问题对我来说有点过于宽泛。