对于我的一个要求,我必须创建N个工作进程例程,这将由一个监视例程监视。当所有工作程序完成时,监视例程必须结束。我的代码以死锁结束,请帮助。
import "fmt"
import "sync"
import "strconv"
func worker(wg *sync.WaitGroup, cs chan string, i int ){
defer wg.Done()
cs<-"worker"+strconv.Itoa(i)
}
func monitorWorker(wg *sync.WaitGroup, cs chan string) {
defer wg.Done()
for i:= range cs {
fmt.Println(i)
}
}
func main() {
wg := &sync.WaitGroup{}
cs := make(chan string)
for i:=0;i<10;i++{
wg.Add(1)
go worker(wg,cs,i)
}
wg.Add(1)
go monitorWorker(wg,cs)
wg.Wait()
}
答案 0 :(得分:13)
您的monitorWorker永远不会死。当所有工人完成后,它继续等待cs。这种僵局是因为没有其他任何东西可以发送到cs,因此wg永远不会达到0.一个可能的解决方法是让监视器在所有工作人员完成时关闭通道。如果for循环在main中,它将结束循环,从main返回,并结束程序。
例如:http://play.golang.org/p/nai7XtTMfr
package main
import (
"fmt"
"strconv"
"sync"
)
func worker(wg *sync.WaitGroup, cs chan string, i int) {
defer wg.Done()
cs <- "worker" + strconv.Itoa(i)
}
func monitorWorker(wg *sync.WaitGroup, cs chan string) {
wg.Wait()
close(cs)
}
func main() {
wg := &sync.WaitGroup{}
cs := make(chan string)
for i := 0; i < 10; i++ {
wg.Add(1)
go worker(wg, cs, i)
}
go monitorWorker(wg, cs)
for i := range cs {
fmt.Println(i)
}
}
编辑:这是对OP的第一条评论的回答。
您的程序有三个部分需要同步。首先,所有员工都需要发送数据。然后您的打印循环需要打印该数据。然后你的主要功能需要返回,从而结束程序。在您的示例中,所有工作人员都会发送数据,所有数据都会被打印出来,但邮件永远不会发送给main,它应该正常返回。
在我的例子中,main执行打印,“monitorWorker”只是在收到需要打印的每个数据时告诉main。这样程序就可以优雅地结束而不是死锁。
如果您坚持将打印循环放在另一个goroutine中,您可以这样做。但是需要将额外的通信发送到main,以便返回。在下一个示例中,我使用通道来确保打印所有数据时的主要结束。
package main
import (
"fmt"
"strconv"
"sync"
)
func worker(wg *sync.WaitGroup, cs chan string, i int) {
defer wg.Done()
cs <- "worker" + strconv.Itoa(i)
}
func monitorWorker(wg *sync.WaitGroup, cs chan string) {
wg.Wait()
close(cs)
}
func printWorker(cs <-chan string, done chan<- bool) {
for i := range cs {
fmt.Println(i)
}
done <- true
}
func main() {
wg := &sync.WaitGroup{}
cs := make(chan string)
for i := 0; i < 10; i++ {
wg.Add(1)
go worker(wg, cs, i)
}
go monitorWorker(wg, cs)
done := make(chan bool, 1)
go printWorker(cs, done)
<-done
}
答案 1 :(得分:0)
如果您知道频道收到的消息数,那么您就可以限制循环;
//c is channel
for a := 1; a <= 3; a++{
fmt.Println(<-c)
}
您还可以将另一个通道(工作人员的状态)传递给工作人员,然后有条件地停止导致死锁的循环。
Ps:这只是一个额外的快速解决方案。并非专门针对您的解决方案。