Goroutine在代码中休眠和死锁。如何解决?

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

Goroutine sleep and deadlock in code. How to solve it?

问题

package main

import "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){
var temp chan int
ch <- t.Value
if t.Left!=nil{go Walk(t.Left,temp)}
if t.Right!=nil{go Walk(t.Right,temp)}
for i := range temp{
ch <- i
}
close(ch)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool

英文:

http://play.golang.org/p/r92-KtQEGl

I am trying to execute this code. It throws a deadlock error.

What am I missing?

package main

import &quot;tour/tree&quot;
import &quot;fmt&quot;

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int){
	var temp chan int
	ch &lt;- t.Value
	if t.Left!=nil{go Walk(t.Left,temp)}
	if t.Right!=nil{go Walk(t.Right,temp)}
	for i := range temp{
		ch &lt;- i
	}
	close(ch)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool

答案1

得分: 2

你需要至少初始化你的通道(如果通道是nil,那么范围将永远阻塞)

  var temp chan int = make(chan int)
  var ch chan int = make(chan int)

参见http://play.golang.org/p/Gh8MZlyd3B(仍然死锁,但至少显示结果)

使用两个临时通道的这个版本不会死锁:http://play.golang.org/p/KsnmKTgZ83

package main

import "tour/tree"
import "fmt"

// Walk遍历树t,将所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
	var temp1 chan int = make(chan int)
	var temp2 chan int = make(chan int)
	ch <- t.Value
	if t.Left != nil {
		go Walk(t.Left, temp1)
	}
	if t.Right != nil {
		go Walk(t.Right, temp2)
	}
	if t.Left != nil {
		for i := range temp1 {
			ch <- i
		}
	}
	if t.Right != nil {
		for i := range temp2 {
			ch <- i
		}
	}
	close(ch)
}

// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool

func main() {
	var ch chan int = make(chan int)
	go Walk(tree.New(1), ch)
	for i := range ch {
		fmt.Println(i)
	}
}
英文:

You need at least to initialize your channels (if the channel is nil, a range would block forever)

  var temp chan int = make(chan int)
  var ch chan int = make(chan int)

See http://play.golang.org/p/Gh8MZlyd3B (still deadlock but at least display results)

This version, using two temp channels, doesn't deadlock: http://play.golang.org/p/KsnmKTgZ83

package main

import &quot;tour/tree&quot;
import &quot;fmt&quot;

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	var temp1 chan int = make(chan int)
	var temp2 chan int = make(chan int)
	ch &lt;- t.Value
	if t.Left != nil {
		go Walk(t.Left, temp1)
	}
	if t.Right != nil {
		go Walk(t.Right, temp2)
	}
	if t.Left != nil {
		for i := range temp1 {
			ch &lt;- i
		}
	}
	if t.Right != nil {
		for i := range temp2 {
			ch &lt;- i
		}
	}
	close(ch)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool

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

答案2

得分: 2

So I did this by by sending in a flag into the Walk function. This way it knows when it can close down the channel. I also think it's important to walk the tree in the right order Left node, Value, Right node.

package main

import (
  "fmt"
  "tour/tree"
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, c chan int, d bool) {
  if t.Left != nil {
    Walk(t.Left, c, false)
  } 
  c <- t.Value
 
  if t.Right != nil {
    Walk(t.Right, c, false)
  }
  if d {
    close(c)
  }
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
  ch1 := make(chan int)
  ch2 := make(chan int)
  go Walk(t1, ch1, true)
  go Walk(t2, ch2, true)
  for {
    v1, ok1 := <-ch1
    v2, ok2 := <-ch2
 
    if v1 != v2 {
      return false
    }
    if ok1 != ok2 {
      return false
    } 
    if !ok1 && !ok2 {
      return true
    }
  }
  return false
}
func main() {
  ch := make(chan int)
  go Walk(tree.New(1), ch, true)

  for i := range ch {
    fmt.Println(i)
  } 
 
  test1 := Same(tree.New(1), tree.New(1))
  test2 := Same(tree.New(1), tree.New(2))

  fmt.Println(test1, test2)
}
英文:

So I did this by by sending in a flag into the Walk function. This way it knows when it can close down the channel. I also think it's important to walk the tree in the right order Left node, Value, Right node.

package main

import (
  &quot;fmt&quot;
  &quot;tour/tree&quot;
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, c chan int, d bool) {
  if t.Left != nil {
    Walk(t.Left, c, false)
  } 
  c &lt;- t.Value
 
  if t.Right != nil {
    Walk(t.Right, c, false)
  }
  if d {
    close(c)
  }
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
  ch1 := make(chan int)
  ch2 := make(chan int)
  go Walk(t1, ch1, true)
  go Walk(t2, ch2, true)
  for {
    v1, ok1 := &lt;-ch1
    v2, ok2 := &lt;-ch2
 
    if v1 != v2 {
      return false
    }
    if ok1 != ok2 {
      return false
    } 
    if !ok1 &amp;&amp; !ok2 {
      return true
    }
  }
  return false
}
func main() {
  ch := make(chan int)
  go Walk(tree.New(1), ch, true)

  for i := range ch {
    fmt.Println(i)
  } 
 
  test1 := Same(tree.New(1), tree.New(1))
  test2 := Same(tree.New(1), tree.New(2))

  fmt.Println(test1, test2)
}

huangapple
  • 本文由 发表于 2012年9月28日 15:47:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/12635793.html
匿名

发表评论

匿名网友

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

确定