生产者消费者模型
电脑能够一边放音乐一边看网页,靠的就是多线程和多进程,在现代软件中,多线程和多进程操作显得不可缺少,尤其是现在处理器几乎全是多核,如果单线程就太可惜了。
任务:
- 生产者消费者模型是广为使用的多线程模型,常用的消息队列也是基于这个模型展开的,因此你可以在网上找到很多相关的代码和解释,图文并茂的那种
- 生产者
Producer
3个p1, p2, p3, 消费者Consumer
3个c1, c2, c3, 传送带最多同时容纳5个数据 - 生产者和消费者一次都只能生产/消耗 1个面包
- 生产者在
rand(0.5, 2)
的时间内产生下一个面包,消费者在rand(0.5, 2)
的时间内消耗下一个面包 - 面包是一个类,具有属性
producer = "xx"
xx是生产者的名字,consumer = "xx"
xx是消费者的名字,生产时改变producer
属性,消费时打上consumer
属性,初始化时两个属性都为空 - 队列加锁,一次只能一个生产者进入放面包,一次只能一个消费者去拿面包,以免造成数据冲突
代码
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type Bread struct {
Consumer, Producer string
}
func timeout(chan2 chan bool) {
time.Sleep(time.Duration(3) * time.Second)
chan2 <- true
}
func Wait() {
t := rand.Intn(1500) + 500
time.Sleep(time.Duration(t) * time.Millisecond)
}
func Print_Bread(t Bread) {
fmt.Printf("%s哼哧哼哧地吃下了一包%s撒下的狗粮!\n", t.Consumer, t.Producer)
}
func Consumer(Name string, chan1 chan Bread, mux *sync.Mutex) {
for true {
Wait()
mux.Lock()
chan2 := make(chan bool)
go timeout(chan2)
select {
case t := <-chan1:
t.Consumer = Name
Print_Bread(t)
case <-chan2:
fmt.Printf("竟然没人撒狗粮,%s很生气\n", Name)
}
mux.Unlock()
}
}
func Producer(Name string, chan1 chan Bread, mux *sync.Mutex) {
var t Bread
for true {
Wait()
mux.Lock()
chan2 := make(chan bool)
go timeout(chan2)
t.Producer = Name
select {
case chan1 <- t:
fmt.Printf("%s撒狗粮啦!\n", Name)
case <-chan2:
fmt.Printf("竟然不能撒狗粮,%s很生气\n", Name)
}
mux.Unlock()
}
}
func main() {
rand.Seed(time.Now().Unix())
chan1 := make(chan Bread, 5)
mux := &sync.Mutex{}
go Producer("司严哥哥", chan1, mux)
go Producer("贾**和她", chan1, mux)
go Producer("张**和她的他", chan1, mux)
go Consumer("汪*泷", chan1, mux)
go Consumer("二哈", chan1, mux)
go Consumer("拉布拉多犬", chan1, mux)
time.Sleep(time.Duration(2) * time.Minute)
}