所有的Go协程都处于休眠状态 – 死锁

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

all go routines are asleep - deadlock

问题

我正在使用Go构建一个工作系统的框架,但是遇到了"fatal error: all goroutines are asleep - deadlock!"的问题。

我使用了两个通道进行协调,一个用于创建任务,另一个用于发送结果。在创建完任务后,我关闭了输入通道。

我的问题是如何关闭输出通道,以便程序可以正确退出。
以下是代码:

package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"time"
)

type Work struct {
	id int
	ts time.Duration
}

const (
	NumWorkers = 5000
	NumJobs    = 100000
)

func worker(in <-chan *Work, out chan<- *Work) {
	for w := range in {
		st := time.Now()
		time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond))))
		w.ts = time.Since(st)
		out <- w
	}
}

func main() {
	wait := flag.Bool("w", false, "wait for <enter> before starting")
	flag.Parse()

	if *wait {
		fmt.Printf("I'm <%d>, press <enter> to continue", os.Getpid())
		reader := bufio.NewReader(os.Stdin)
		reader.ReadString('\n')
	}

	Run()
}

func Run() {
	in, out := make(chan *Work, 100), make(chan *Work, 100)
	for i := 0; i < NumWorkers; i++ {
		go worker(in, out)
	}
	go createJobs(in)
	receiveResults(out)
}

func createJobs(queue chan<- *Work) {
	for i := 0; i < NumJobs; i++ {
		work := &Work{i, 0}
		queue <- work
	}
	close(queue)
}

func receiveResults(completed <-chan *Work) {
	for w := range completed {
		log.Printf("job %d completed in %s", w.id, w.ts)
	}
}

希望能帮到你 所有的Go协程都处于休眠状态 – 死锁

英文:

I'm building the skeleton of a worker system using Go and I'm getting the "fatal error: all goroutines are asleep - deadlock!".

I am using two channels for coordination, one to create the jobs and the second to send the results. After creating the jobs I close the input channel.

My question is how I close the output channel so the program can exit correctly.
The code is:

package main
import (
&quot;bufio&quot;
&quot;flag&quot;
&quot;fmt&quot;
&quot;log&quot;
&quot;math/rand&quot;
&quot;os&quot;
&quot;time&quot;
)
type Work struct {
id int
ts time.Duration
}
const (
NumWorkers = 5000
NumJobs    = 100000
)
func worker(in &lt;-chan *Work, out chan&lt;- *Work) {
for w := range in {
st := time.Now()
time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond))))
w.ts = time.Since(st)
out &lt;- w
}
}
func main() {
wait := flag.Bool(&quot;w&quot;, false, &quot;wait for &lt;enter&gt; before starting&quot;)
flag.Parse()
if *wait {
fmt.Printf(&quot;I&#39;m &lt;%d&gt;, press &lt;enter&gt; to continue&quot;, os.Getpid())
reader := bufio.NewReader(os.Stdin)
reader.ReadString(&#39;\n&#39;)
}
Run()
}
func Run() {
in, out := make(chan *Work, 100), make(chan *Work, 100)
for i := 0; i &lt; NumWorkers; i++ {
go worker(in, out)
}
go createJobs(in)
receiveResults(out)
}
func createJobs(queue chan&lt;- *Work) {
for i := 0; i &lt; NumJobs; i++ {
work := &amp;Work{i, 0}
queue &lt;- work
}
close(queue)
}
func receiveResults(completed &lt;-chan *Work) {
for w := range completed {
log.Printf(&quot;job %d completed in %s&quot;, w.id, w.ts)
}
}

Any help is appreciated 所有的Go协程都处于休眠状态 – 死锁

答案1

得分: 1

我错过了你在原始答案中关于你知道死锁原因的部分。

  • 你提到了WaitGroup,它基本上只是一个信号量。
  • 你可以使用另一个“控制”通道,工作人员在完成时发出信号。
func worker(ctrl chan<- bool, in <-chan *Work, out chan<- *Work) {
    for w := range in {
        st := time.Now()
        time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond))))
        w.ts = time.Since(st)
        out <- w
    }
    ctrl <- true
}

func control(ctrl <-chan bool, numWorkers int, out chan<- *Work) {
    for i := 0; i < numWorkers; i++ {
        <-ctrl
    }
    close(out)
}

原始答案中提到:

你对completed通道进行了range操作:

for w := range completed {
    log.Printf("job %d completed in %s", w.id, w.ts)
}

但是该通道从未关闭。

英文:

I missed the part about you knowing the cause of deadlock in original answer.

  • You mentioned WaitGroup, that is basically just a semaphore
  • You could use another "control" channel that workers sinal on when they are done

-

func worker(ctrl chan&lt;- bool, in &lt;-chan *Work, out chan&lt;- *Work) {
for w := range in {
st := time.Now()
time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond))))
w.ts = time.Since(st)
out &lt;- w
}
ctrl &lt;- true
}
func control(ctrl &lt;-chan bool, numWorkers int, out chan&lt;- *Work) {
for i=0; i&lt;numWorkers; i++ {
&lt;-ctrl
}
close(out)
}

original answer:

You do a range on completed:

for w := range completed {
log.Printf(&quot;job %d completed in %s&quot;, w.id, w.ts)
}

but that channel is never closed

huangapple
  • 本文由 发表于 2014年1月30日 06:49:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/21444380.html
匿名

发表评论

匿名网友

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

确定