如何关闭递归函数内的通道

时间:2018-04-19 14:39:34

标签: go

我试图找到一个类似的问题,但我不能,所以我在这里问:

我在递归函数中使用close(ch)。我需要关闭通道以终止range循环。但是,由于函数是递归的,close会多次运行,这给了我:

  恐慌:关闭封闭的通道

如果我发表评论close(ch)声明,我会收到:

  

致命错误:所有goroutine都睡着了 - 死锁!

请在下面找到我的代码:

package main

import "golang.org/x/tour/tree"
import "fmt"

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
    ch<-(t.Value)
    if t.Left != nil { Walk(t.Left, ch) }
    if t.Right != nil { Walk(t.Right, ch) }
    close(ch) // => How to close a channel inside recursive function? ***
    return
}

func main() {
    ch := make(chan int)
    go Walk(tree.New(1), ch)
    for i := range ch {
        fmt.Print(i, " ")
    }
}

3 个答案:

答案 0 :(得分:8)

关闭递归函数之外的通道:

func Walk(t *tree.Tree, ch chan int) {
    ch<-(t.Value)
    if t.Left != nil { Walk(t.Left, ch) }
    if t.Right != nil { Walk(t.Right, ch) }
}

func main() {
    ch := make(chan int)
    go func() {
        defer close(ch)
        Walk(tree.New(1), ch)
    }()
    for i := range ch {
        fmt.Print(i, " ")
    }
}

答案 1 :(得分:1)

Cerise Limón的答案很好。我只想提一下,在闭包内使用read()不是强制性的:

defer

package main import ( "fmt" "golang.org/x/tour/tree" ) func Walk(t *tree.Tree, ch chan int) { if t.Left != nil { Walk(t.Left, ch) } ch <- t.Value if t.Right != nil { Walk(t.Right, ch) } } func main() { ch := make(chan int) go func() { Walk(tree.New(1), ch) close(ch) }() for i := range ch { fmt.Print(i, " ") } } 函数完成后,通道将关闭,并且两个动作都在单独的goroutine中执行。

如果我们使用

Walk

我们正在启动goroutine,但立即关闭当前通道中的频道。


由于我想在递归函数中关闭通道,所以最终这样做:

go Walk(tree.New(1), ch)
close(ch)

那样,递归调用将不会关闭通道,并且只允许func Walk(t *tree.Tree, ch chan int, closeAtTheEnd bool) { if t.Left != nil { // fmt.Println("Walk the Left of", t.Value) Walk(t.Left, ch, false) } // fmt.Println("Send to the channel:", t.Value) ch <- t.Value if t.Right != nil { // fmt.Println("Walk the Right of", t.Value) Walk(t.Right, ch, false) } if closeAtTheEnd { close(ch) } } 的第一个调用来执行此操作(树从根节点开始,并且在双向行走后关闭通道)。

Walk

答案 2 :(得分:0)

我发现这种书写方式更加简洁

class Department(models.Model):
    name= models.CharField(max_length=100, unique=True)
    def __unicode__(self):
        return self.name[:50] 


class DeviceGroup(models.Model):
    name= models.CharField(max_length=100, unique=True)
    def __unicode__(self):
        return self.name[:50]