gpt4 book ai didi

GO语言: fatal error: all goroutines are asleep - deadlock

转载 作者:IT老高 更新时间:2023-10-28 13:04:02 28 4
gpt4 key购买 nike

下面的代码适用于硬编码的 JSON 数据,但是当我从文件中读取 JSON 数据时不起作用。我收到 fatal error: all goroutines are sleep - 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

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

package main

import (
"bytes"
"fmt"
"os/exec"
"time"
"encoding/json"
"os"
"sync"
)

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)
}
}

type Content struct {
Username string `json:"username"`
Ip string `json:"ip"`
}

func main() {
var wg sync.WaitGroup

var source []Content
var hosts []string
data := json.NewDecoder(os.Stdin)
data.Decode(&source)

for _, value := range source {
hosts = append(hosts, value.Username + "@" + value.Ip)
}

var c chan string = make(chan string)
go listener(c)

for i := 0; i < len(hosts); i++ {
wg.Add(1)
c <- hosts[i]
defer wg.Done()
}

var input string
fmt.Scanln(&input)

wg.Wait()
}

输出

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$

HOSTS.TXT

[
{
"username":"user1",
"ip":"111.79.154.111"
},
{
"username":"user2",
"ip":"111.79.190.222"
}
]

最佳答案

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

来自 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.

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

同步goroutine的最简单代码:

package main

import "fmt"
import "sync"

var wg sync.WaitGroup // 1

func routine() {
defer wg.Done() // 3
fmt.Println("routine finished")
}

func main() {
wg.Add(1) // 2
go routine() // *
wg.Wait() // 4
fmt.Println("main finished")
}

用于同步多个 goroutines

package main

import "fmt"
import "sync"

var wg sync.WaitGroup // 1

func routine(i int) {
defer wg.Done() // 3
fmt.Printf("routine %v finished\n", i)
}

func main() {
for i := 0; i < 10; i++ {
wg.Add(1) // 2
go routine(i) // *
}
wg.Wait() // 4
fmt.Println("main finished")
}

WaitGroup 按执行顺序使用。

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

* 实际参数为evaluated before starting new gouroutine .因此需要在 wg.Add(1) 之前显式评估它们,这样可能出现 panic 的代码就不会留下增加的计数器。

使用

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

而不是

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

关于GO语言: fatal error: all goroutines are asleep - deadlock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26927479/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com