无论是生产者还是消费者各自是独立的,但彼此又相关联。今日我用go语言模拟一个并发的生产和消费场景。
背景是这样的:
```
有一个生产饮料的工厂, 工厂里有2个生产机器, 每生产一个产品要花费1h,生产的产品会自动放到仓库中,仓库可容纳5个这样的产品,有3个员工,他们每一个人需要花费0.8h 将1个产品搬运到小区中地摊上等待售卖,每隔1.5h会有一个顾客来到摊子上等待购买这种产品(这种商品是通过抢购获取,与来得早晚无关),如果等待了2h依然没买到就会离开。每一天,如果工厂里的产品材料耗尽,那么机器将停运,再员工要将所有商品售出后,地摊也会被回收,工厂进入停业状态。
```
机器和员工之间的工作是独立的,员工的工作依赖机器生产的产品,而顾客依赖地摊上的产品,使用一个协程代表一个实体(机器/员工/顾客),彼此间使用channel通讯,模拟依赖关系。
程序如下:
package main
import (
"fmt"
"sync"
"time"
)
/*------------------ 场景实现*/
func main() {
wg := sync.WaitGroup{}
//设置工厂仓库容量
cl := make(chan int, 5)
//设置工厂员工令牌
py := make(chan struct{}, 3)
//设置工厂机器令牌
jq := make(chan struct{}, 2)
//设置容纳原材料的容器(2个容器)
rq := make(chan int, 2)
//设置小区地摊在售产品
yl := make(chan int)
//停工信号
ab := make(chan struct{})
//停业信号
st := make(chan struct{})
//工厂是否停工
aborted := func() bool {
select {
case <- ab:
return true;
default:
return false
}
}
//工厂是否停业
factoryStop := func() bool {
select {
case <- st:
return true
default:
return false
}
}
//3个员工开始上班
for i := 0; i < 3; i++ {
wg.Add(1)
py <- struct{}{}
go func(id int, cl <-chan int) {
defer wg.Done();
for {
var x int
var timeout bool
//可用劳动力-1
<- py
//员工只有在在机器停工后, 且售卖完仓库的产品后才能停工
if len(cl) == 0 && len(jq) == 2 && aborted() {
fmt.Printf("工人:`%d` 停工...\n", id)
return
}
//延时轮询, 避免死锁
select {
case x = <-cl:
case <-time.After(800 * time.Millisecond):
py <- struct{}{}
timeout = true
}
if timeout {
continue
}
fmt.Printf("工人:`%d` %d-搬运中...\n", id, x)
time.Sleep(500*time.Millisecond) //搬运耗时: 0.5h
yl <- x //产品售卖中
time.Sleep(300*time.Millisecond) //返回: 0.3h
//补充劳动力
fmt.Printf("工人:`%d` 回厂了...\n", id)
//可用劳动力+1
py <- struct{}{}
}
}(i, cl)
}
//2台机器开始工作
for i := 0; i < 2; i++ {
wg.Add(1)
jq <- struct{}{}
go func (id int, in chan<- int, out <-chan int) {
defer wg.Done()
for {
var p int
var timeout bool
//可用机器-1
<- jq
//即使停机, 机器也需要将容器中的原材料给消耗完毕
if len(out) == 0 && aborted() {
fmt.Println("机器停工了...")
return
}
//延时轮询, 避免死锁
select {
case p = <-out:
case <-time.After(time.Second):
timeout = true
jq <- struct{}{}
}
if timeout {
continue
}
fmt.Printf("jq:`%d` %d-生产中...\n", id, p)
time.Sleep(time.Second) //耗时1h
//产品入库
in <-p
//可用机器+1
jq <- struct{}{}
}
//defer wg.Done()
}(i, cl, rq)
}
go func(yl <-chan int) {
//不考虑有多少顾客排队, 也不考虑排队顺序
for {
//地摊还在不?
if factoryStop() {
break
}
go func(yl <-chan int) {
//抢购商品
select {
//等待
case i := <-yl:
fmt.Printf("luck, 抢到了 %d\n", i)
//地摊收回, 等待者离开
case <-st:
fmt.Println("今天卖完了... 离开吧")
//等了2h后, 离开
case <-time.After(2*time.Second):
fmt.Println("不耐烦地走了")
}
}(yl)
fmt.Println("一个顾客加入抢购...")
time.Sleep(1500*time.Millisecond)
}
}(yl)
//工厂开工
number := 10 //原材料数量
for i := 0; i < number; i++ {
//往容器中装入原材料
rq <- i
}
//停工
close(ab)
//等待
wg.Wait()
//停业
close(st)
close(jq) //关闭机器
close(cl) //清理库存
close(py) //员工下班
close(rq) //清理容器
//工厂关门
fmt.Println("工厂停业")
}
上面仅实现了提供差不多能满足市场需要,可以通过调整参数模拟出"供不应求“的场景,再或者调整员工的销售规则(并且允许囤货等)模拟“供大于求”的场景。