GOLANG:致命错误:所有的goroutine都处于休眠状态 – 死锁

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

GOLANG: fatal error: all goroutines are asleep - deadlock

问题

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "bufio"
  7. "reflect"
  8. )
  9. func runTheCommand(ch chan<- string, cmD string) {
  10. ouT,_ := exec.Command("sh","-c",cmD).Output()
  11. ch <- string(ouT)
  12. }
  13. // Readln returns a single line (without the ending \n) from the input buffered reader. An error is returned iff there is an error with the buffered reader.
  14. func Readln(r *bufio.Reader) (string, error) {
  15. var (
  16. isPrefix bool = true
  17. err error = nil
  18. line, ln []byte
  19. )
  20. for isPrefix && err == nil {
  21. line, isPrefix, err = r.ReadLine()
  22. ln = append(ln, line...)
  23. }
  24. return string(ln),err
  25. }
  26. func main() {
  27. var chans = []chan string{}
  28. f, _ := os.Open("../tmpStatus.config")
  29. r := bufio.NewReader(f)
  30. cmD, e := Readln(r)
  31. for e == nil {
  32. ch := make(chan string)
  33. chans = append(chans, ch)
  34. go runTheCommand(ch,cmD)
  35. cmD,e = Readln(r)
  36. }
  37. cases := make([]reflect.SelectCase, len(chans))
  38. for i, ch := range chans {
  39. cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
  40. }
  41. remaining := len(cases)
  42. for remaining > 0 {
  43. chosen, value, ok := reflect.Select(cases)
  44. if !ok {
  45. cases[chosen].Chan = reflect.ValueOf(nil)
  46. remaining -= 1
  47. continue
  48. }
  49. fmt.Printf("%s", value.String())
  50. }
  51. }

这段代码正确地打印出了从通道接收到的所有值。但最后却出现了以下错误:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [select]: reflect.rselect(0xc200283480, 0x22, 0x22, 0xffffffffffffffff, 0x0, ...)
/usr/local/go/src/pkg/runtime/chan.c:1212 +0x10d
reflect.Select(0xc200066800, 0x22, 0x22, 0x1, 0x0, ...)
/usr/local/go/src/pkg/reflect/value.go:1957 +0x1fb

我是一个Go的新手。我参考了谷歌并设法编写了一个可工作的代码。我并没有完全理解这个脚本是如何工作的,特别是reflect包的命令。我在这里的目的是并行执行../tmpStatus.config文件中列出的Unix命令并打印结果。我对Go提供的并发特性感到兴奋,所以决定试一试。现在它打印结果的速度非常快。到目前为止,我一直在用Python一个一个地执行这些命令。我在go version go1.1.2 linux/amd64上运行了这个脚本,它安装在一个自定义位置。有没有人知道为什么会发生死锁?

英文:
  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;os&quot;
  5. &quot;os/exec&quot;
  6. &quot;bufio&quot;
  7. &quot;reflect&quot;
  8. )
  9. func runTheCommand(ch chan&lt;- string, cmD string) {
  10. ouT,_ := exec.Command(&quot;sh&quot;,&quot;-c&quot;,cmD).Output()
  11. ch &lt;- string(ouT)
  12. }
  13. // Readln returns a single line (without the ending \n) from the input buffered reader. An error is returned iff there is an error with the buffered reader.
  14. func Readln(r *bufio.Reader) (string, error) {
  15. var (isPrefix bool = true
  16. err error = nil
  17. line, ln []byte
  18. )
  19. for isPrefix &amp;&amp; err == nil {
  20. line, isPrefix, err = r.ReadLine()
  21. ln = append(ln, line...)
  22. }
  23. return string(ln),err
  24. }
  25. func main() {
  26. var chans = []chan string{}
  27. f, _ := os.Open(&quot;../tmpStatus.config&quot;)
  28. r := bufio.NewReader(f)
  29. cmD, e := Readln(r)
  30. for e == nil {
  31. ch := make(chan string)
  32. chans = append(chans, ch)
  33. go runTheCommand(ch,cmD)
  34. cmD,e = Readln(r)
  35. }
  36. cases := make([]reflect.SelectCase, len(chans))
  37. for i, ch := range chans {
  38. cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
  39. }
  40. remaining := len(cases)
  41. for remaining &gt; 0 {
  42. chosen, value, ok := reflect.Select(cases)
  43. if !ok {
  44. cases[chosen].Chan = reflect.ValueOf(nil)
  45. remaining -= 1
  46. continue
  47. }
  48. fmt.Printf(&quot;%s&quot;, value.String())
  49. }
  50. }

This code is correctly printing out all the received values from the channels.
But in the end it is exiting with the below error :

>fatal error: all goroutines are asleep - deadlock!

> goroutine 1 [select]: reflect.rselect(0xc200283480, 0x22, 0x22,
> 0xffffffffffffffff, 0x0, ...)
> /usr/local/go/src/pkg/runtime/chan.c:1212 +0x10d
reflect.Select(0xc200066800, 0x22, 0x22, 0x1, 0x0, ...)
> /usr/local/go/src/pkg/reflect/value.go:1957 +0x1fb

I am a newbee at GO. I referred google and somehow managed to write a working code. I didn't understand fully how this script works especially the reflect package commands. My intention here is to execute the unix commands listed in ../tmpStatus.config file parallely and print out the results. I am excited by the concurrency features offered by GO and hence decided to give it a try. Now it is printing the results so fast. Till now, I was doing this in python one by one.
I ran this script in go version go1.1.2 linux/amd64 installed to a custom location.
Any idea why the deadlock is happening ?

答案1

得分: 2

看起来你正在尝试从文件中读取内容,然后将工作分配给多个工作器(扇出)。我在你的代码中没有看到任何关闭通道的操作。你可以参考这个链接https://gist.github.com/kylewolfe/7c54018a9ed16517c0dd,里面有一个我所指的模式的示例。对于文件的每一行,你可以将其读入一个通道,然后x个工作器可以从该通道中读取内容(并进行处理/工作)。

英文:

It looks like you are trying to to read from a file and then split the work across multiple workers (fan out). I do not see any closing of channels in your code. See https://gist.github.com/kylewolfe/7c54018a9ed16517c0dd for an example of the pattern I'm referring to. For each line of your file, you would read into the one channel, where x workers would read from it (and reflect / do work).

huangapple
  • 本文由 发表于 2015年2月3日 21:51:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/28300581.html
匿名

发表评论

匿名网友

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

确定