GO语言:致命错误:所有goroutine都在睡眠中-死锁

下面的代码与硬编码的JSON数据一起正常工作,但是当我从文件中读取JSON数据时不起作用。我得到fatal error: all goroutines

are asleep - deadlock使用时的错误sync.WaitGroup

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

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$

[

{

"username":"user1",

"ip":"111.79.154.111"

},

{

"username":"user2",

"ip":"111.79.190.222"

}

]

回答:

从语言规范

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

因此,您需要等待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")

}

并用于同步多个goroutine

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. 增加柜台。这必须在主goroutine中完成,因为由于内存模型的保证,不能保证新启动的goroutine将在4之前执行。
  3. 减少计数器。这必须在goroutine的出口处完成。使用延迟调用,我们确保无论函数结束如何结束,只要函数结束,都将调用它。
  4. 等待计数器达到0。必须在主goroutine中执行此操作,以防止程序退出。

*实际参数在开始新的鱼肉素之前要进行评估。因此,需要在对它们进行显式评估之前,wg.Add(1)使可能出现恐慌的代码不会留下增加的计数器。

param := f(x)

wg.Add(1)

go g(param)

代替

wg.Add(1)

go g(f(x))

以上是 GO语言:致命错误:所有goroutine都在睡眠中-死锁 的全部内容, 来源链接: utcz.com/qa/408527.html

回到顶部