quit channel在go-tour解决方案的binarytrees_quit.go文件中的目的是什么?

huangapple go评论66阅读模式
英文:

What is the purpose of quit channel in binarytrees_quit.go in go-tour solutions?

问题

我不太理解binarytrees_quit.go中quit channel变量的目的。或者说,我是否漏掉了重要的一点。我可以理解接收器可以向quit发送值,以告诉go例程返回或退出。但我不认为这是这种情况。它只是为了确保Walk例程一直存在,直到Same执行完毕吗?即使这样,go例程也会一直存在,因为通道没有缓冲区。即使是这种情况,也没有任何意义。请帮助我理解。

提前感谢!

英文:

I don't quite understand the purpose of quit channel variable in binarytrees_quit.go. Or, am I missing the important point here. I can understand that receiver can send value to quit to tell the go routine to return or exit. But I don't think that it's the case here. Is it just to make sure that Walk routines stick around till Same finishes the execution? Won't go routine stick around just because channels are not buffered. Even if this is the case, that does not make any sense. Please help me to understand.

Thanks in advance!

答案1

得分: 2

你可以在《Go for gophers - GopherCon closing keynote - 2014年4月25日 - Andrew Gerrand》中找到详细的方法。

提前停止
在walker中添加一个quit通道,以便我们可以在中途停止它。

func walk(t *tree.Tree, ch chan int, quit chan struct{}) {
    if t.Left != nil {
        walk(t.Left, ch, quit)
    }
    select {
    case ch <- t.Value:
    // vvvvvvvvvvvv
    case <-quit:
        return
    }
    // ^^^^^^^^^^^^
    if t.Right != nil {
        walk(t.Right, ch, quit)
    }
}

创建一个quit通道并将其传递给每个walker。
通过在Same退出时关闭quit,可以终止任何正在运行的walker

func Same(t1, t2 *tree.Tree) bool {
    // vvvvvvvvvvvv
    quit := make(chan struct{})
    defer close(quit)
    w1, w2 := Walk(t1, quit), Walk(t2, quit)
    // ^^^^^^^^^^^^
    for {
        v1, ok1 := <-w1
        v2, ok2 := <-w2
        if v1 != v2 || ok1 != ok2 {
            return false
        }
        if !ok1 {
            return true
        }
    }
}

Andrew补充道:

为什么不直接杀死goroutine?

Goroutine对Go代码来说是不可见的。它们无法被杀死或等待。
你必须自己构建。

这是有原因的:

一旦Go代码知道它在哪个线程中运行,你就会得到线程局部性。
线程局部性破坏了并发模型

  • 通道只是值;它们完全适合类型系统。
  • Goroutine对Go代码来说是不可见的;这使得你可以在任何地方进行并发。

少即是多。

英文:

You can see that approached detailed in "Go for gophers - GopherCon closing keynote - 25 April 2014 - Andrew Gerrand "

> Stopping early
> Add a quit channel to the walker so we can stop it mid-stride.

func walk(t *tree.Tree, ch chan int, quit chan struct{}) {
    if t.Left != nil {
        walk(t.Left, ch, quit)
    }
    select {
    case ch &lt;- t.Value:
    // vvvvvvvvvvvv
    case &lt;-quit:
        return
    }
    // ^^^^^^^^^^^^
    if t.Right != nil {
        walk(t.Right, ch, quit)
    }
}

> Create a quit channel and pass it to each walker.
> By closing quit when the Same exits, any running walkers are terminated.

func Same(t1, t2 *tree.Tree) bool {
    // vvvvvvvvvvvv
    quit := make(chan struct{})
    defer close(quit)
    w1, w2 := Walk(t1, quit), Walk(t2, quit)
    // ^^^^^^^^^^^^
    for {
        v1, ok1 := &lt;-w1
        v2, ok2 := &lt;-w2
        if v1 != v2 || ok1 != ok2 {
            return false
        }
        if !ok1 {
            return true
        }
    }
}

Andrew adds:

> Why not just kill the goroutines?

> Goroutines are invisible to Go code. They can't be killed or waited on.
You have to build that yourself.

> There's a reason:

> As soon as Go code knows in which thread it runs you get thread-locality.
Thread-locality defeats the concurrency model
.

> - Channels are just values; they fit right into the type system.

  • Goroutines are invisible to Go code; this gives you concurrency anywhere.

> Less is more.

huangapple
  • 本文由 发表于 2015年3月4日 22:38:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/28857190.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定