GO 语言:致命错误:所有 goroutine 都处于睡眠状态 - 死锁

下面的代码适用于硬编码的 JSON 数据,但是当我从文件中读取 JSON 数据时不起作用。我得到fatal error: all goroutines are asleep - deadlock使用时的错误sync.WaitGroup。


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


package main


import (

    "bytes"

    "fmt"

    "os/exec"

    "time"

)


func connect(host string) {

    cmd := exec.Command("ssh", host, "uptime")

    var out bytes.Buffer

    cmd.Stdout = &out

    err := cmd.Run()

    if err != nil {

        fmt.Println(err)

    }

    fmt.Printf("%s: %q\n", host, out.String())

    time.Sleep(time.Second * 2)

    fmt.Printf("%s: DONE\n", host)

}


func listener(c chan string) {

    for {

        host := <-c

        go connect(host)

    }

}


func main() {

    hosts := [2]string{"user1@111.79.154.111", "user2@111.79.190.222"}

    var c chan string = make(chan string)

    go listener(c)


    for i := 0; i < len(hosts); i++ {

        c <- hosts[i]

    }

    var input string

    fmt.Scanln(&input)

}

输出:


user@user-VirtualBox:~/go$ go run channel.go

user1@111.79.154.111: " 09:46:40 up 86 days, 18:16,  0 users,  load average: 5"

user2@111.79.190.222: " 09:46:40 up 86 days, 17:27,  1 user,  load average: 9"

user1@111.79.154.111: DONE

user2@111.79.190.222: DONE

输出


user@user-VirtualBox:~/go$ go run deploy.go < hosts.txt 

user1@111.79.154.111: " 09:46:40 up 86 days, 18:16,  0 users,  load average: 5"

user2@111.79.190.222: " 09:46:40 up 86 days, 17:27,  1 user,  load average: 9"

user1@111.79.154.111 : DONE

user2@111.79.190.222: DONE

fatal error: all goroutines are asleep - deadlock!


goroutine 1 [semacquire]:

sync.runtime_Semacquire(0xc210000068)

    /usr/lib/go/src/pkg/runtime/sema.goc:199 +0x30

sync.(*WaitGroup).Wait(0xc210047020)

    /usr/lib/go/src/pkg/sync/waitgroup.go:127 +0x14b

main.main()

    /home/user/go/deploy.go:64 +0x45a


goroutine 3 [chan receive]:

main.listener(0xc210038060)

    /home/user/go/deploy.go:28 +0x30

created by main.main

    /home/user/go/deploy.go:53 +0x30b

exit status 2

user@user-VirtualBox:~/go$

主机.TXT


[

   {

      "username":"user1",

      "ip":"111.79.154.111"

   },

   {

      "username":"user2",

      "ip":"111.79.190.222"

   }

]


慕盖茨4494581
浏览 559回答 3
3回答

料青山看我应如是

Go 程序在 main 函数结束时结束。从语言规范程序执行首先初始化主包,然后调用函数 main。当该函数调用返回时,程序退出。它不会等待其他(非主)goroutine 完成。因此,您需要等待 goroutine 完成。对此的常见解决方案是使用sync.WaitGroup对象。最简单的同步 goroutine 的代码:package mainimport "fmt"import "sync"var wg sync.WaitGroup // 1func routine() {&nbsp; &nbsp; defer wg.Done() // 3&nbsp; &nbsp; fmt.Println("routine finished")}func main() {&nbsp; &nbsp; wg.Add(1) // 2&nbsp; &nbsp; go routine() // *&nbsp; &nbsp; wg.Wait() // 4&nbsp; &nbsp; fmt.Println("main finished")}并用于同步多个 goroutinepackage mainimport "fmt"import "sync"var wg sync.WaitGroup // 1func routine(i int) {&nbsp; &nbsp; defer wg.Done() // 3&nbsp; &nbsp; fmt.Printf("routine %v finished\n", i)}func main() {&nbsp; &nbsp; for i := 0; i < 10; i++ {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1) // 2&nbsp; &nbsp; &nbsp; &nbsp; go routine(i) // *&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait() // 4&nbsp; &nbsp; fmt.Println("main finished")}WaitGroup 按执行顺序使用。全局变量的声明。使其全局化是使其对所有函数和方法可见的最简单方法。增加计数器。这必须在 main goroutine 中完成,因为由于内存模型保证,不能保证新启动的 goroutine 会在 4 之前执行。减少计数器。这必须在 goroutine 退出时完成。使用延迟调用,我们确保无论何时函数结束,无论它如何结束,它都会被调用。等待计数器达到 0。这必须在 main goroutine 中完成以防止程序退出。*在启动新 gouroutine 之前评估实际参数。因此需要在之前明确评估它们,wg.Add(1)以便可能出现恐慌的代码不会留下增加的计数器。用param := f(x)wg.Add(1)go g(param)代替wg.Add(1)go g(f(x))
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go