预期输出以及工作池中的死锁问题

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

Expected output as well as deadlock in a worker pool

问题

我正在学习Go语言并发,并编写了一个必备的工作池示例,其中有N个工作和M个工作者(N > M)。我遇到了一个死锁问题(all goroutines are asleep),我无法解决;然而,在死锁发生之前,我也得到了预期的输出,这让我更加困惑。请问有人可以指出我做错了什么吗?

我的代码如下:

package main

import (
	"fmt"
	"sync"
)

// 使用通道和WaitGroup实现一个简单的工作池。
// 我们的工作者从输入通道中读取整数,并将其平方写入输出通道。

func addJobs(jobsCh chan<- int, wg *sync.WaitGroup) {
	// 100个要处理的数字(工作)
	for i := 1; i < 101; i++ {
		jobsCh <- i
	}
	wg.Done()
}

func worker(jobsCh <-chan int, resultsCh chan<- int, wg2 *sync.WaitGroup) {
	for num := range jobsCh {
		resultsCh <- num * num
	}
	wg2.Done()
}

func addWorkers(jobsCh <-chan int, resultsCh chan<- int, wg *sync.WaitGroup) {
	var wg2 sync.WaitGroup
	// 10个工作者
	for i := 0; i < 10; i++ {
		wg2.Add(1)
		go worker(jobsCh, resultsCh, &wg2)
	}
	wg.Done()
}

func readResults(resultsCh <-chan int, wg *sync.WaitGroup) {
	for sq := range resultsCh {
		fmt.Printf("%v ", sq)
	}
	wg.Done()
}

func main() {
	var wg sync.WaitGroup
	jobsCh := make(chan int)
	resultsCh := make(chan int)

	wg.Add(1)
	go addJobs(jobsCh, &wg)

	wg.Add(1)
	go addWorkers(jobsCh, resultsCh, &wg)

	wg.Add(1)
	go readResults(resultsCh, &wg)

	wg.Wait()
}

这会按预期打印数字的平方(顺序随机),但也会遇到死锁问题。请参考这个 playground 链接。 预期输出以及工作池中的死锁问题

英文:

I'm learning Go concurrency and wrote the obligatory worker pool example, where there are N pieces of work and M workers (N > M). I'm running into a deadlock (all goroutines are asleep), which I can't figure out; however, I'm also getting the expected output before the deadlock occurs, which has me even more confused. Can someone please point out the things I'm doing wrong?

My code is this:

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
)

// A simple worker pool implementation using channels and WaitGroups.
// Our workers simply read from a channel of integers from an input
// channel and write their squares to an output channel.

func addJobs(jobsCh chan&lt;- int, wg *sync.WaitGroup) {
	// 100 numbers to crunch (jobs)
	for i := 1; i &lt; 101; i++ {
		jobsCh &lt;- i
	}
	wg.Done()
}

func worker(jobsCh &lt;-chan int, resultsCh chan&lt;- int, wg2 *sync.WaitGroup) {
	for num := range jobsCh {
		resultsCh &lt;- num * num
	}
	wg2.Done()
}

func addWorkers(jobsCh &lt;-chan int, resultsCh chan&lt;- int, wg *sync.WaitGroup) {
	var wg2 sync.WaitGroup
	// 10 workers
	for i := 0; i &lt; 10; i++ {
		wg2.Add(1)
		go worker(jobsCh, resultsCh, &amp;wg2)
	}
	wg.Done()
}

func readResults(resultsCh &lt;-chan int, wg *sync.WaitGroup) {
	for sq := range resultsCh {
		fmt.Printf(&quot;%v &quot;, sq)
	}
	wg.Done()
}

func main() {
	var wg sync.WaitGroup
	jobsCh := make(chan int)
	resultsCh := make(chan int)

	wg.Add(1)
	go addJobs(jobsCh, &amp;wg)

	wg.Add(1)
	go addWorkers(jobsCh, resultsCh, &amp;wg)

	wg.Add(1)
	go readResults(resultsCh, &amp;wg)

	wg.Wait()
}

This prints the squares of the numbers (in random order), as expected, but also runs into a deadlock. Please see this playground link. 预期输出以及工作池中的死锁问题

答案1

得分: 2

关闭jobsCh以使工作线程退出:

func addJobs(jobsCh chan<- int, wg *sync.WaitGroup) {
    // 100个要处理的数字(工作)
    for i := 1; i < 101; i++ {
        jobsCh <- i
    }
    close(jobsCh)  // <-- 添加这一行
    wg.Done()
}

当工作线程完成后,关闭resultsCh以使结果循环退出:

func addWorkers(jobsCh <-chan int, resultsCh chan<- int, wg *sync.WaitGroup) {
    var wg2 sync.WaitGroup
    // 10个工作线程
    for i := 0; i < 10; i++ {
        wg2.Add(1)
        go worker(jobsCh, resultsCh, &wg2)
    }
    wg2.Wait()       // <-- 添加这一行
    close(resultsCh) // 和这一行
    wg.Done()
}
英文:

Close jobsCh to cause workers to exit:

func addJobs(jobsCh chan&lt;- int, wg *sync.WaitGroup) {
// 100 numbers to crunch (jobs)
for i := 1; i &lt; 101; i++ {
jobsCh &lt;- i
}
close(jobsCh)  // &lt;-- add this line
wg.Done()
}

After workers are done, close resultsCh to cause results loop to exit:

func addWorkers(jobsCh &lt;-chan int, resultsCh chan&lt;- int, wg *sync.WaitGroup) {
var wg2 sync.WaitGroup
// 10 workers
for i := 0; i &lt; 10; i++ {
wg2.Add(1)
go worker(jobsCh, resultsCh, &amp;wg2)
}
wg2.Wait()       // &lt;-- add this line
close(resultsCh) // and this line
wg.Done()
}

huangapple
  • 本文由 发表于 2022年7月18日 22:52:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/73024321.html
匿名

发表评论

匿名网友

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

确定