要延迟去处理就可以了
package main import ( "fmt" "sync" "time" ) var global = sync.WaitGroup{} // A车传送给B车的通道 var ch1 = make(chan *material, 3) // B车传送给C车的通道 var ch2 = make(chan *material, 3) // 食材 type material struct { // 食材名称 name string // 食材数量 count byte // A车处理所需花费时间,单位秒 elapsedTimeA uint // B车处理所需花费时间,单位秒 elapsedTimeB uint // C车处理所需花费时间,单位秒 elapsedTimeC uint } func main() { global.Add(3) // 所有需要处理的食材 materials := []*material{ {"白菜", 12, 2, 1, 1}, {"青菜", 12, 1, 1, 1}, {"胡萝卜", 12, 1, 1, 1}, } start := time.Now() go A(materials) go B() go C() global.Wait() cost := time.Since(start) fmt.Printf("总耗时:%s\n", cost) } func A(materials []*material) { fmt.Printf("A车出发\n") // 循环处理每种食材 for _, ele := range materials { var worker = sync.WaitGroup{} worker.Add(3) // 3名工人分别处理每种食材的1/3 for i := 0; i < 3; i++ { go func(index int, ele2 *material) { fmt.Printf("A车工人[%d]正在清洗食材[%s],数量[%d],预计耗时[%d]秒\n", index, ele2.name, ele2.count/3, ele2.elapsedTimeA) // 睡眠模拟处理食材耗时 time.Sleep(time.Second * time.Duration(ele2.elapsedTimeA)) worker.Done() }(i, ele) } // 等待所有工人都处理完毕后,把处理后的食材传送给B车 worker.Wait() fmt.Printf("A车食材[%s]正在运往B车\n", ele.name) ch1 <- ele } fmt.Printf("A车任务结束\n") global.Done() } func B() { fmt.Printf("B车出发\n") // 循环处理3种食材 for i := 0; i < 3; i++ { // 从通道取不到数据时会阻塞,只有通道关闭时ok才等于false,所以下面的if判断可以忽略 ele, ok := <-ch1 if !ok { break } fmt.Printf("B车接收到A车食材[%s]\n", ele.name) var worker = sync.WaitGroup{} worker.Add(3) for j := 0; j < 3; j++ { go func(index int, ele2 *material) { fmt.Printf("B车工人[%d]正在加工食材[%s],数量[%d],预计耗时[%d]秒\n", index, ele2.name, ele2.count/3, ele2.elapsedTimeB) // 睡眠模拟处理食材耗时 time.Sleep(time.Second * time.Duration(ele2.elapsedTimeB)) worker.Done() }(j, ele) } // 等待所有工人都处理完毕后,把处理后的食材传送给C车 worker.Wait() fmt.Printf("B车食材[%s]正在运往C车\n", ele.name) ch2 <- ele } fmt.Printf("B车任务结束\n") global.Done() } func C() { fmt.Printf("C车出发\n") for i := 0; i < 3; i++ { // 从通道取不到数据时会阻塞,只有通道关闭时ok才等于false,所以下面的if判断可以忽略 ele, ok := <-ch2 if !ok { break } fmt.Printf("C车接收到B车食材[%s]\n", ele.name) var worker = sync.WaitGroup{} worker.Add(3) for j := 0; j < 3; j++ { go func(index int, ele2 *material) { fmt.Printf("C车工人[%d]正在装载食材[%s],数量[%d],预计耗时[%d]秒\n", index, ele2.name, ele2.count/3, ele2.elapsedTimeC) // 睡眠模拟处理食材耗时 time.Sleep(time.Second * time.Duration(ele2.elapsedTimeC)) worker.Done() }(j, ele) } worker.Wait() } fmt.Printf("C车任务结束\n") global.Done() }
这是因为ch<- 1 这个操作,是阻塞操作,就是说 遇到了 a<-1 代码就不走了,什么时候代码往下走?必须等到ch里面的消息被读出去才会继续走
可以简单改为:
ch := make(chan int) // fmt.Println(ch) go func() { ch <- 1 }() // 输出channel go func() { fmt.Println(<-ch) }() time.Sleep(time.Second*2)
你用你的想法用代码来试一下比对一下吧
小伙伴客气啦!其实流水线形式也是可以的,这里只是提供了一种可能的案例
在提问中提到的流水线形式,可能会存在一种,由于频繁使用channel传输数据的形式,而造成一定程度的额外耗时
所以我们在设计并发代码的时候,在某些为了通过并发加速计算的场景下,通常会尽可能地避免使用到channel
?抱歉,没理解你的意思,能否给点提示?
已经添加上了吧