其次,为了等待生产者和消费者 goroutine 运行完成,我们封装了匿名函数。需要注意的是, 匿名函数接受 ID 作为参数,每次调用会把 i+1 传递过去,这是函数闭包的特性;如果直接使用下面的代码:
for i:=0; i<NumOfProducers;i++ {
go func(){
p := newProducer(i+1)
p.Run(buffer)
prodWg.Done()
}()
}
不使用参数传递,而是直接使用 i+1,那么所有的生产者内部变量 producerID 其实都指向同一个值,也就是说它们的 ID 将会一样。
最后,我们在 main 函数中创建的 channel 是双向的,但是生产者接收的 channel 是只写的,而消费者接受的 channel 是只读的。这是因为在做参数传递时,go 会自动做类型转换。
运行以上程序,可能会得到类似下面的结果:
producer 2 put data 0
producer 1 put data 0
producer 3 put data 0
consumer 2 got: data 0 from producer 3
consumer 1 got: data 0 from producer 2
consumer 5 got: data 0 from producer 1
producer 1 put data 1
consumer 3 got: data 1 from producer 1
producer 3 put data 1
consumer 4 got: data 1 from producer 3
producer 2 put data 1
consumer 2 got: data 1 from producer 2
producer 3 put data 2
producer 1 put data 2
consumer 1 got: data 2 from producer 3
producer 2 put data 2
consumer 3 got: data 2 from producer 2
consumer 5 got: data 2 from producer 1
producer 3 put data 3
consumer 4 got: data 3 from producer 3
producer 1 put data 3
consumer 2 got: data 3 from producer 1
producer 2 put data 3
consumer 1 got: data 3 from producer 2
producer 3 put data 4
producer 1 put data 4
consumer 5 got: data 4 from producer 1
consumer 3 got: data 4 from producer 3
producer 2 put data 4
consumer 4 got: data 4 from producer 2
consumer 2: detect channel close
consumer 3: detect channel close
consumer 5: detect channel close
consumer 1: detect channel close
consumer 4: detect channel close
exit...