需求
fatal error: all goroutines are asleep - deadlock!
代码
package main
import (
"fmt"
"log"
"math/rand"
"sync"
"time"
)
type Row struct {
Id int `json:"id"`
}
type Report struct {
Name string `json:"name"`
}
type Bag struct {
Reports []Report `json:"reports"`
I int `json:"i"`
J int `json:"j"`
}
func GetRows() (rows []Row) {
rows = make([]Row, 0)
for i := 0; i < rand.Intn(10); i++ {
rows = append(rows, Row{Id: i})
}
return
}
func GetReports(m, n int) (reports []Report) {
reports = make([]Report, 0)
for i := 0; i < rand.Intn(100); i++ {
reports = append(reports, Report{Name: fmt.Sprintf("r: in %d rows[%d] report %d", m, n, i)})
}
return
}
func main() {
var (
cLimit = 3 // 线程限制
wg = sync.WaitGroup{}
)
c := make(chan int, cLimit)
c2 := make(chan int, 10)
cReport := make(chan Bag, 100)
defer close(c)
defer close(cReport)
go func() {
log.Println("in Rec Start")
defer func() {
log.Println("in Rec Finish")
}()
//Rec:
for {
select {
case r, ok := <-cReport:
if !ok {
c2 <- 1
}
log.Printf("rec %v from %d rows[%d] len=%d\n ", ok, r.I, r.J, len(r.Reports))
}
}
}()
for i := 0; i < 10; i++ {
rows := GetRows()
wg.Add(1)
c <- 1
log.Printf("add %d rows=%d", i, len(rows))
go func(rows []Row, i int) {
log.Println("in ", i)
for j := 0; j < len(rows); j++ {
rs := GetReports(i, j)
log.Printf("in %d rows[%d] get rs:%d to send\n", i, j, len(rs))
cReport <- Bag{Reports: rs, I: i, J: j}
time.Sleep(time.Second * time.Duration(rand.Intn(7)))
}
defer func() {
wg.Done()
log.Println("leave ", i)
}()
<-c
}(rows, i)
if i%cLimit == 0 {
fmt.Println()
}
}
log.Println("after loop")
Rec:
for {
select {
case r, ok := <-cReport:
if !ok {
break Rec
}
log.Printf("rec %v from %d rows[%d] len=%d\n ", ok, r.I, r.J, len(r.Reports))
}
}
log.Println("after work")
wg.Wait()
select {
case v, ok := <-c2:
fmt.Println("v,ok = ", v, ok)
break
}
log.Println("Finish")
}
里面开了2个通道 c 和 cReport,c是为了限制协程的数量,使用了wg来进行限制线程数量。
cReport 是报告的结果的通道,但现在问题是,如果加了 c 来限制协程数量,cReport 就会报错deadlock 死锁。
如何实现,既可以将数据从 协程中接收,又可以限制协程数量?