慕粉1453012542
2022-02-09
注意 无缓冲区通道, 两端是可以保证原子性的
打印不出来
不是因为通道没来得及输出
而是 print 这个函数没来得及刷新 os 缓冲区就被主进程强行关掉了,
慕雪6235644
2021-08-12
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()
}
慕粉第一号
2021-08-07
这是因为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)
慕粉第一号
2021-08-07
大菠萝965661
2021-07-31
你用你的想法用代码来试一下比对一下吧
bongIO好
2020-11-07
小伙伴客气啦!其实流水线形式也是可以的,这里只是提供了一种可能的案例
在提问中提到的流水线形式,可能会存在一种,由于频繁使用channel传输数据的形式,而造成一定程度的额外耗时
所以我们在设计并发代码的时候,在某些为了通过并发加速计算的场景下,通常会尽可能地避免使用到channel
宝慕林0163075
2020-07-04
?抱歉,没理解你的意思,能否给点提示?
羊毛梦
2020-06-03
已经添加上了吧