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

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

GO language: fatal error: all goroutines are asleep - deadlock

问题

以下是翻译好的内容:

下面的代码在使用硬编码的JSON数据时运行良好,但在从文件中读取JSON数据时不起作用。在使用sync.WaitGroup时,我遇到了fatal error: all goroutines are asleep - deadlock错误。

使用硬编码的JSON数据的工作示例:

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "os/exec"
  6. "time"
  7. )
  8. func connect(host string) {
  9. cmd := exec.Command("ssh", host, "uptime")
  10. var out bytes.Buffer
  11. cmd.Stdout = &out
  12. err := cmd.Run()
  13. if err != nil {
  14. fmt.Println(err)
  15. }
  16. fmt.Printf("%s: %q\n", host, out.String())
  17. time.Sleep(time.Second * 2)
  18. fmt.Printf("%s: DONE\n", host)
  19. }
  20. func listener(c chan string) {
  21. for {
  22. host := <-c
  23. go connect(host)
  24. }
  25. }
  26. func main() {
  27. hosts := [2]string{"user1@111.79.154.111", "user2@111.79.190.222"}
  28. var c chan string = make(chan string)
  29. go listener(c)
  30. for i := 0; i < len(hosts); i++ {
  31. c <- hosts[i]
  32. }
  33. var input string
  34. fmt.Scanln(&input)
  35. }

输出:

  1. user@user-VirtualBox:~/go$ go run channel.go
  2. user1@111.79.154.111: " 09:46:40 up 86 days, 18:16, 0 users, load average: 5"
  3. user2@111.79.190.222: " 09:46:40 up 86 days, 17:27, 1 user, load average: 9"
  4. user1@111.79.154.111: DONE
  5. user2@111.79.190.222: DONE

不起作用 - 使用读取JSON数据文件的示例:

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "os/exec"
  6. "time"
  7. "encoding/json"
  8. "os"
  9. "sync"
  10. )
  11. func connect(host string) {
  12. cmd := exec.Command("ssh", host, "uptime")
  13. var out bytes.Buffer
  14. cmd.Stdout = &out
  15. err := cmd.Run()
  16. if err != nil {
  17. fmt.Println(err)
  18. }
  19. fmt.Printf("%s: %q\n", host, out.String())
  20. time.Sleep(time.Second * 2)
  21. fmt.Printf("%s: DONE\n", host)
  22. }
  23. func listener(c chan string) {
  24. for {
  25. host := <-c
  26. go connect(host)
  27. }
  28. }
  29. type Content struct {
  30. Username string `json:"username"`
  31. Ip string `json:"ip"`
  32. }
  33. func main() {
  34. var wg sync.WaitGroup
  35. var source []Content
  36. var hosts []string
  37. data := json.NewDecoder(os.Stdin)
  38. data.Decode(&source)
  39. for _, value := range source {
  40. hosts = append(hosts, value.Username + "@" + value.Ip)
  41. }
  42. var c chan string = make(chan string)
  43. go listener(c)
  44. for i := 0; i < len(hosts); i++ {
  45. wg.Add(1)
  46. c <- hosts[i]
  47. defer wg.Done()
  48. }
  49. var input string
  50. fmt.Scanln(&input)
  51. wg.Wait()
  52. }

输出:

  1. user@user-VirtualBox:~/go$ go run deploy.go < hosts.txt
  2. user1@111.79.154.111: " 09:46:40 up 86 days, 18:16, 0 users, load average: 5"
  3. user2@111.79.190.222: " 09:46:40 up 86 days, 17:27, 1 user, load average: 9"
  4. user1@111.79.154.111: DONE
  5. user2@111.79.190.222: DONE
  6. fatal error: all goroutines are asleep - deadlock!
  7. goroutine 1 [semacquire]:
  8. sync.runtime_Semacquire(0xc210000068)
  9. /usr/lib/go/src/pkg/runtime/sema.goc:199 +0x30
  10. sync.(*WaitGroup).Wait(0xc210047020)
  11. /usr/lib/go/src/pkg/sync/waitgroup.go:127 +0x14b
  12. main.main()
  13. /home/user/go/deploy.go:64 +0x45a
  14. goroutine 3 [chan receive]:
  15. main.listener(0xc210038060)
  16. /home/user/go/deploy.go:28 +0x30
  17. created by main.main
  18. /home/user/go/deploy.go:53 +0x30b
  19. exit status 2
  20. user@user-VirtualBox:~/go$

HOSTS.TXT:

  1. [
  2. {
  3. "username":"user1",
  4. "ip":"111.79.154.111"
  5. },
  6. {
  7. "username":"user2",
  8. "ip":"111.79.190.222"
  9. }
  10. ]
英文:

Code below works fine with hard coded JSON data however doesn't work when I read JSON data from a file. I'm getting fatal error: all goroutines are asleep - deadlock error when using sync.WaitGroup.

WORKING EXAMPLE WITH HARD-CODED JSON DATA:

  1. package main
  2. import (
  3. &quot;bytes&quot;
  4. &quot;fmt&quot;
  5. &quot;os/exec&quot;
  6. &quot;time&quot;
  7. )
  8. func connect(host string) {
  9. cmd := exec.Command(&quot;ssh&quot;, host, &quot;uptime&quot;)
  10. var out bytes.Buffer
  11. cmd.Stdout = &amp;out
  12. err := cmd.Run()
  13. if err != nil {
  14. fmt.Println(err)
  15. }
  16. fmt.Printf(&quot;%s: %q\n&quot;, host, out.String())
  17. time.Sleep(time.Second * 2)
  18. fmt.Printf(&quot;%s: DONE\n&quot;, host)
  19. }
  20. func listener(c chan string) {
  21. for {
  22. host := &lt;-c
  23. go connect(host)
  24. }
  25. }
  26. func main() {
  27. hosts := [2]string{&quot;user1@111.79.154.111&quot;, &quot;user2@111.79.190.222&quot;}
  28. var c chan string = make(chan string)
  29. go listener(c)
  30. for i := 0; i &lt; len(hosts); i++ {
  31. c &lt;- hosts[i]
  32. }
  33. var input string
  34. fmt.Scanln(&amp;input)
  35. }

OUTPUT:

  1. user@user-VirtualBox:~/go$ go run channel.go
  2. user1@111.79.154.111: &quot; 09:46:40 up 86 days, 18:16, 0 users, load average: 5&quot;
  3. user2@111.79.190.222: &quot; 09:46:40 up 86 days, 17:27, 1 user, load average: 9&quot;
  4. user1@111.79.154.111: DONE
  5. user2@111.79.190.222: DONE

NOT WORKING - EXAMPLE WITH READING JSON DATA FILE:

  1. package main
  2. import (
  3. &quot;bytes&quot;
  4. &quot;fmt&quot;
  5. &quot;os/exec&quot;
  6. &quot;time&quot;
  7. &quot;encoding/json&quot;
  8. &quot;os&quot;
  9. &quot;sync&quot;
  10. )
  11. func connect(host string) {
  12. cmd := exec.Command(&quot;ssh&quot;, host, &quot;uptime&quot;)
  13. var out bytes.Buffer
  14. cmd.Stdout = &amp;out
  15. err := cmd.Run()
  16. if err != nil {
  17. fmt.Println(err)
  18. }
  19. fmt.Printf(&quot;%s: %q\n&quot;, host, out.String())
  20. time.Sleep(time.Second * 2)
  21. fmt.Printf(&quot;%s: DONE\n&quot;, host)
  22. }
  23. func listener(c chan string) {
  24. for {
  25. host := &lt;-c
  26. go connect(host)
  27. }
  28. }
  29. type Content struct {
  30. Username string `json:&quot;username&quot;`
  31. Ip string `json:&quot;ip&quot;`
  32. }
  33. func main() {
  34. var wg sync.WaitGroup
  35. var source []Content
  36. var hosts []string
  37. data := json.NewDecoder(os.Stdin)
  38. data.Decode(&amp;source)
  39. for _, value := range source {
  40. hosts = append(hosts, value.Username + &quot;@&quot; + value.Ip)
  41. }
  42. var c chan string = make(chan string)
  43. go listener(c)
  44. for i := 0; i &lt; len(hosts); i++ {
  45. wg.Add(1)
  46. c &lt;- hosts[i]
  47. defer wg.Done()
  48. }
  49. var input string
  50. fmt.Scanln(&amp;input)
  51. wg.Wait()
  52. }

OUTPUT

  1. user@user-VirtualBox:~/go$ go run deploy.go &lt; hosts.txt
  2. user1@111.79.154.111: &quot; 09:46:40 up 86 days, 18:16, 0 users, load average: 5&quot;
  3. user2@111.79.190.222: &quot; 09:46:40 up 86 days, 17:27, 1 user, load average: 9&quot;
  4. user1@111.79.154.111 : DONE
  5. user2@111.79.190.222: DONE
  6. fatal error: all goroutines are asleep - deadlock!
  7. goroutine 1 [semacquire]:
  8. sync.runtime_Semacquire(0xc210000068)
  9. /usr/lib/go/src/pkg/runtime/sema.goc:199 +0x30
  10. sync.(*WaitGroup).Wait(0xc210047020)
  11. /usr/lib/go/src/pkg/sync/waitgroup.go:127 +0x14b
  12. main.main()
  13. /home/user/go/deploy.go:64 +0x45a
  14. goroutine 3 [chan receive]:
  15. main.listener(0xc210038060)
  16. /home/user/go/deploy.go:28 +0x30
  17. created by main.main
  18. /home/user/go/deploy.go:53 +0x30b
  19. exit status 2
  20. user@user-VirtualBox:~/go$

HOSTS.TXT

  1. [
  2. {
  3. &quot;username&quot;:&quot;user1&quot;,
  4. &quot;ip&quot;:&quot;111.79.154.111&quot;
  5. },
  6. {
  7. &quot;username&quot;:&quot;user2&quot;,
  8. &quot;ip&quot;:&quot;111.79.190.222&quot;
  9. }
  10. ]

答案1

得分: 64

Go程序在主函数结束时结束。

根据语言规范

程序的执行从初始化主包开始,然后调用main函数。当该函数调用返回时,程序退出。它不会等待其他(非主)goroutine完成。

因此,你需要等待goroutine完成。常见的解决方案是使用sync.WaitGroup对象。

同步goroutine的最简单的代码:

  1. package main
  2. import "fmt"
  3. import "sync"
  4. var wg sync.WaitGroup // 1
  5. func routine() {
  6. defer wg.Done() // 3
  7. fmt.Println("routine finished")
  8. }
  9. func main() {
  10. wg.Add(1) // 2
  11. go routine() // *
  12. wg.Wait() // 4
  13. fmt.Println("main finished")
  14. }

用于同步多个goroutine的代码:

  1. package main
  2. import "fmt"
  3. import "sync"
  4. var wg sync.WaitGroup // 1
  5. func routine(i int) {
  6. defer wg.Done() // 3
  7. fmt.Printf("routine %v finished\n", i)
  8. }
  9. func main() {
  10. for i := 0; i < 10; i++ {
  11. wg.Add(1) // 2
  12. go routine(i) // *
  13. }
  14. wg.Wait() // 4
  15. fmt.Println("main finished")
  16. }

WaitGroup的使用顺序如下:

  1. 声明全局变量。将其声明为全局变量是使其对所有函数和方法可见的最简单方法。
  2. 增加计数器。这必须在主goroutine中完成,因为不能保证新启动的goroutine会在4之前执行,这是由于内存模型的保证
  3. 减少计数器。这必须在goroutine退出时完成。使用延迟调用,确保它将在函数结束时被调用,无论如何结束。
  4. 等待计数器达到0。这必须在主goroutine中完成,以防止程序退出。

* 实际参数在启动新的goroutine之前进行评估。因此,在wg.Add(1)之前需要显式评估它们,以防止可能导致计数器增加的代码发生恐慌。

使用:

  1. param := f(x)
  2. wg.Add(1)
  3. go g(param)

而不是:

  1. wg.Add(1)
  2. go g(f(x))
英文:

Go program ends when the main function ends.

From the language specification

> Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

Therefore, you need to wait for your goroutines to finish. The common solution for this is to use sync.WaitGroup object.

The simplest possible code to synchronize goroutine:

  1. package main
  2. import &quot;fmt&quot;
  3. import &quot;sync&quot;
  4. var wg sync.WaitGroup // 1
  5. func routine() {
  6. defer wg.Done() // 3
  7. fmt.Println(&quot;routine finished&quot;)
  8. }
  9. func main() {
  10. wg.Add(1) // 2
  11. go routine() // *
  12. wg.Wait() // 4
  13. fmt.Println(&quot;main finished&quot;)
  14. }

And for synchronizing multiple goroutines

  1. package main
  2. import &quot;fmt&quot;
  3. import &quot;sync&quot;
  4. var wg sync.WaitGroup // 1
  5. func routine(i int) {
  6. defer wg.Done() // 3
  7. fmt.Printf(&quot;routine %v finished\n&quot;, i)
  8. }
  9. func main() {
  10. for i := 0; i &lt; 10; i++ {
  11. wg.Add(1) // 2
  12. go routine(i) // *
  13. }
  14. wg.Wait() // 4
  15. fmt.Println(&quot;main finished&quot;)
  16. }

WaitGroup usage in order of execution.

  1. Declaration of global variable. Making it global is the easiest way to make it visible to all functions and methods.
  2. Increasing the counter. This must be done in main goroutine because there is no guarantee that newly started goroutine will execute before 4 due to memory model guarantees.
  3. Decreasing the counter. This must be done at the exit of goroutine. Using deferred call, we make sure that it will be called whenever function ends no matter but no matter how it ends.
  4. Waiting for the counter to reach 0. This must be done in main goroutine to prevent program exit.

* The actual parameters are evaluated before starting new gouroutine. Thus it is needed to evaluate them explicitly before wg.Add(1) so the possibly panicking code would not leave increased counter.

Use

  1. param := f(x)
  2. wg.Add(1)
  3. go g(param)

instead of

  1. wg.Add(1)
  2. go g(f(x))

答案2

得分: 5

感谢Grzegorz Żur提供的非常好的详细解释。
我想指出的一件事是,通常需要进行线程处理的函数不会在main()中,所以我们会有类似这样的代码:

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "math/rand"
  8. "os"
  9. "reflect"
  10. "regexp"
  11. "strings"
  12. "sync"
  13. "time"
  14. )
  15. var wg sync.WaitGroup // 非常重要的全局声明,否则会出现“fatal error: all goroutines are asleep - deadlock!”的错误
  16. func doSomething(arg1 arg1Type) {
  17. // 治愈了癌症
  18. }
  19. func main() {
  20. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  21. randTime := r.Intn(10)
  22. wg.Add(1)
  23. go doSomething(randTime)
  24. wg.Wait()
  25. fmt.Println("等待所有线程完成")
  26. }

我想指出的是,全局声明的wg对于所有线程在main()之前完成非常关键。

英文:

Thanks for the very nice and detailed explanation Grzegorz Żur.
One thing that I want to point it out that typically the func that needs to be threaded wont be in main(), so we would have something like this:

  1. package main
  2. import (
  3. &quot;bufio&quot;
  4. &quot;fmt&quot;
  5. &quot;io&quot;
  6. &quot;io/ioutil&quot;
  7. &quot;math/rand&quot;
  8. &quot;os&quot;
  9. &quot;reflect&quot;
  10. &quot;regexp&quot;
  11. &quot;strings&quot;
  12. &quot;sync&quot;
  13. &quot;time&quot;
  14. )
  15. var wg sync.WaitGroup // VERY IMP to declare this globally, other wise one //would hit &quot;fatal error: all goroutines are asleep - deadlock!&quot;
  16. func doSomething(arg1 arg1Type) {
  17. // cured cancer
  18. }
  19. func main() {
  20. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  21. randTime := r.Intn(10)
  22. wg.Add(1)
  23. go doSomething(randTime)
  24. wg.Wait()
  25. fmt.Println(&quot;Waiting for all threads to finish&quot;)
  26. }

The thing that I want to point it out is that global declaration of wg is very crucial for all threads to finish before main()

答案3

得分: 1

  1. package main
  2. /*
  3. 模拟从线程发送消息进行处理,
  4. 并将响应(处理结果)发送回线程
  5. */
  6. import (
  7. "fmt"
  8. "math/rand"
  9. "time"
  10. )
  11. type (
  12. TChans []chan TMsgRec
  13. TMsgRec struct {
  14. name string // 通道名称
  15. rid int //-1 或者 TChans 中响应通道的索引
  16. msg string // 消息
  17. note string // 注释
  18. }
  19. TThRec struct { // 线程
  20. name string
  21. rid int // TChans 中响应通道的索引(或者为 -1)
  22. job chan TMsgRec // 发送消息到接收器的通道
  23. resp chan TMsgRec // 返回给线程的响应通道
  24. }
  25. )
  26. func main() {
  27. index := -1
  28. Chans := make(TChans, 100)
  29. index = NewChanIndex(&Chans)
  30. Job := Chans[index] // 从线程发送消息到接收器的通道
  31. index = NewChanIndex(&Chans) // 线程 "1th" 的响应通道索引
  32. go ping(TThRec{name: "1th", job: Job, rid: index, resp: Chans[index]})
  33. index = NewChanIndex(&Chans) // 线程 "2th" 的响应通道索引
  34. go ping(TThRec{name: "2th", job: Job, rid: index, resp: Chans[index]})
  35. Receiver(Job, Chans)
  36. }
  37. func Receiver(c chan TMsgRec, pChans TChans) {
  38. var v TMsgRec
  39. for {
  40. select {
  41. case v = <-c: // 接收消息
  42. {
  43. if v.rid > -1 {
  44. //pChans[v.rid] <- TMsgRec{name: v.name, rid: -1, msg: fmt.Sprint(v.msg, ":receiver "), note: ""}
  45. go worker(v, pChans[v.rid])
  46. }
  47. }
  48. default:
  49. {
  50. //fmt.Println("receiver")
  51. SleepM(2)
  52. }
  53. }
  54. }
  55. }
  56. func worker(v TMsgRec, r chan TMsgRec) {
  57. // 模拟 SQL 查询或其他处理
  58. SleepM(rand.Intn(50))
  59. v.msg = v.msg + ":worker"
  60. r <- v
  61. }
  62. func waitResponse(d chan TMsgRec, pTimeout int) (bool, TMsgRec) {
  63. var v TMsgRec
  64. for {
  65. select {
  66. case v = <-d:
  67. {
  68. return true, v
  69. }
  70. case <-time.After(10 * time.Second):
  71. {
  72. return false, v
  73. }
  74. }
  75. }
  76. }
  77. func ping(pParam TThRec) {
  78. SleepM(10)
  79. var v TMsgRec
  80. ok := true
  81. i := 0
  82. for i < 500 {
  83. if ok {
  84. ok = false
  85. pParam.job <- TMsgRec{name: pParam.name, rid: pParam.rid, msg: fmt.Sprint(i), note: ""}
  86. i++
  87. }
  88. if pParam.rid > -1 {
  89. if !ok {
  90. ok, v = waitResponse(pParam.resp, 10)
  91. if ok {
  92. fmt.Println(v.name, v.msg)
  93. SleepM(1)
  94. } else {
  95. fmt.Println(pParam.name, "响应超时")
  96. }
  97. }
  98. } else {
  99. SleepM(1)
  100. }
  101. }
  102. fmt.Println(v.name, "-- 结束 --")
  103. }
  104. func NewChanIndex(pC *TChans) int {
  105. for i, v := range *pC {
  106. if v == nil {
  107. (*pC)[i] = make(chan TMsgRec)
  108. return i
  109. }
  110. }
  111. return -1
  112. }
  113. func FreeRespChan(pC *TChans, pIndex int) {
  114. if (*pC)[pIndex] != nil {
  115. close((*pC)[pIndex]) // 关闭通道
  116. (*pC)[pIndex] = nil
  117. }
  118. }
  119. func SleepM(pMilliSec int) { // 休眠毫秒数
  120. time.Sleep(time.Duration(pMilliSec) * time.Millisecond)
  121. }
英文:
  1. package main
  2. /*
  3. Simulation for sending messages from threads for processing,
  4. and getting a response (processing result) to the thread
  5. */
  6. import (
  7. &quot;fmt&quot;
  8. &quot;math/rand&quot;
  9. &quot;time&quot;
  10. )
  11. type (
  12. TChans []chan TMsgRec
  13. TMsgRec struct {
  14. name string //channel name
  15. rid int //-1 or index of response channel in TChans
  16. msg string // message
  17. note string // comment
  18. }
  19. TThRec struct { // for thread
  20. name string
  21. rid int // index of response channel in TChans (or -1)
  22. job chan TMsgRec // chanel for send message to Receiver
  23. resp chan TMsgRec // response channel back to thread
  24. }
  25. )
  26. func main() {
  27. index := -1
  28. Chans := make(TChans, 100)
  29. index = NewChanIndex(&amp;Chans)
  30. Job := Chans[index] // channel for send message from threads to Receiver
  31. index = NewChanIndex(&amp;Chans) // channel index for response, for the thread &quot;1th&quot;
  32. go ping(TThRec{name: &quot;1th&quot;, job: Job, rid: index, resp: Chans[index]})
  33. index = NewChanIndex(&amp;Chans) // channel index for response, for the thread &quot;2th&quot;
  34. go ping(TThRec{name: &quot;2th&quot;, job: Job, rid: index, resp: Chans[index]})
  35. Receiver(Job, Chans)
  36. }
  37. func Receiver(c chan TMsgRec, pChans TChans) {
  38. var v TMsgRec
  39. for {
  40. select {
  41. case v = &lt;-c: // receive message
  42. {
  43. if v.rid &gt; -1 {
  44. //pChans[v.rid] &lt;- TMsgRec{name: v.name, rid: -1, msg: fmt.Sprint(v.msg, &quot;:receiver &quot;), note: &quot;&quot;}
  45. go worker(v, pChans[v.rid])
  46. }
  47. }
  48. default:
  49. {
  50. //fmt.Println(&quot;receiver&quot;)
  51. SleepM(2)
  52. }
  53. }
  54. }
  55. }
  56. func worker(v TMsgRec, r chan TMsgRec) {
  57. // simulation SQL query, or auther process
  58. SleepM(rand.Intn(50))
  59. v.msg = v.msg + &quot;:worker&quot;
  60. r &lt;- v
  61. }
  62. func waitResponse(d chan TMsgRec, pTimeout int) (bool, TMsgRec) {
  63. var v TMsgRec
  64. for {
  65. select {
  66. case v = &lt;-d:
  67. {
  68. return true, v
  69. }
  70. case &lt;-time.After(10 * time.Second):
  71. {
  72. return false, v
  73. }
  74. }
  75. }
  76. }
  77. func ping(pParam TThRec) {
  78. SleepM(10)
  79. var v TMsgRec
  80. ok := true
  81. i := 0
  82. for i &lt; 500 {
  83. if ok {
  84. ok = false
  85. pParam.job &lt;- TMsgRec{name: pParam.name, rid: pParam.rid, msg: fmt.Sprint(i), note: &quot;&quot;}
  86. i++
  87. }
  88. if pParam.rid &gt; -1 {
  89. if !ok {
  90. ok, v = waitResponse(pParam.resp, 10)
  91. if ok {
  92. fmt.Println(v.name, v.msg)
  93. SleepM(1)
  94. } else {
  95. fmt.Println(pParam.name, &quot;response timeout&quot;)
  96. }
  97. }
  98. } else {
  99. SleepM(1)
  100. }
  101. }
  102. fmt.Println(v.name, &quot;-- end --&quot;)
  103. }
  104. func NewChanIndex(pC *TChans) int {
  105. for i, v := range *pC {
  106. if v == nil {
  107. (*pC)[i] = make(chan TMsgRec)
  108. return i
  109. }
  110. }
  111. return -1
  112. }
  113. func FreeRespChan(pC *TChans, pIndex int) {
  114. if (*pC)[pIndex] != nil {
  115. close((*pC)[pIndex]) //close channel
  116. (*pC)[pIndex] = nil
  117. }
  118. }
  119. func SleepM(pMilliSec int) { // sleep millisecounds
  120. time.Sleep(time.Duration(pMilliSec) * time.Millisecond)
  121. }

答案4

得分: -2

请尝试以下代码片段:

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "os/exec"
  6. "time"
  7. "sync"
  8. )
  9. func connect(host string, wg *sync.WaitGroup) {
  10. defer wg.Done()
  11. cmd := exec.Command("ssh", host, "uptime")
  12. var out bytes.Buffer
  13. cmd.Stdout = &out
  14. err := cmd.Run()
  15. if err != nil {
  16. fmt.Println(err)
  17. }
  18. fmt.Printf("%s: %q\n", host, out.String())
  19. time.Sleep(time.Second * 2)
  20. fmt.Printf("%s: DONE\n", host)
  21. }
  22. func listener(c chan string, wg *sync.WaitGroup) {
  23. for {
  24. host, ok := <-c
  25. // check channel is closed or not
  26. if !ok {
  27. break
  28. }
  29. go connect(host, wg)
  30. }
  31. }
  32. func main() {
  33. var wg sync.WaitGroup
  34. hosts := [2]string{"user1@111.79.154.111", "user2@111.79.190.222"}
  35. var c chan string = make(chan string)
  36. go listener(c, &wg)
  37. for i := 0; i < len(hosts); i++ {
  38. wg.Add(1)
  39. c <- hosts[i]
  40. }
  41. close(c)
  42. var input string
  43. fmt.Scanln(&input)
  44. wg.Wait()
  45. }

希望对你有帮助!

英文:

try this code snippest

  1. package main
  2. import (
  3. &quot;bytes&quot;
  4. &quot;fmt&quot;
  5. &quot;os/exec&quot;
  6. &quot;time&quot;
  7. &quot;sync&quot;
  8. )
  9. func connect(host string, wg *sync.WaitGroup) {
  10. defer wg.Done()
  11. cmd := exec.Command(&quot;ssh&quot;, host, &quot;uptime&quot;)
  12. var out bytes.Buffer
  13. cmd.Stdout = &amp;out
  14. err := cmd.Run()
  15. if err != nil {
  16. fmt.Println(err)
  17. }
  18. fmt.Printf(&quot;%s: %q\n&quot;, host, out.String())
  19. time.Sleep(time.Second * 2)
  20. fmt.Printf(&quot;%s: DONE\n&quot;, host)
  21. }
  22. func listener(c chan stringwg *sync.WaitGroup) {
  23. for {
  24. hostok := &lt;-c
  25. // check channel is closed or not
  26. if !ok{
  27. break
  28. }
  29. go connect(host)
  30. }
  31. }
  32. func main() {
  33. var wg sync.WaitGroup
  34. hosts := [2]string{&quot;user1@111.79.154.111&quot;, &quot;user2@111.79.190.222&quot;}
  35. var c chan string = make(chan string)
  36. go listener(c)
  37. for i := 0; i &lt; len(hosts); i++ {
  38. wg.Add(1)
  39. c &lt;- hosts[i]
  40. }
  41. close(c)
  42. var input string
  43. fmt.Scanln(&amp;input)
  44. wg.Wait()
  45. }

huangapple
  • 本文由 发表于 2014年11月14日 18:09:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/26927479.html
匿名

发表评论

匿名网友

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

确定