本人小白,自学golang,记录日常。

在学习channel后打算自己设计一个生产者消费者模型,以下是记录过程中遇见的一些难点和最后的解决方案:

    要求:

    汽车厂生产汽车交给店员,有10个经销商从店员这买汽车,店员一次只能持有固定的数量。如果店中有空位再放汽车话则通知生产者继续生产;如果店员没有汽车了,店员让经销商等一下,如果店中有汽车了再通知经销商取一下,缺货一定程度再扩建一个厂继续生产。

       在设计这串代码中总结的自己认为比较关键的点:

        1. 当生产者(汽车厂)和消费者(经销商)两个goroutine同时共用一个channel同时在读写时,如何保证写入channel的信息让另外一个goroutine读取而不是写入goroutine本身去读取?

       我思考后给出的解决方案是用延时功能在写入channel信息后加

time.Sleep(1 * time.Second)

这样让本身goroutine不会读取自己写入的数据

*********************************************************************************

对于上面这个问题是之前的想法,其实想错了,解决这个问题的本身原因是判断通道是否为空,我加延时功能只是碰巧解决了问题而并没有理解透彻,应该为当缓存充足且生产速率>=消费速率的时候,通道不为空,才能解决以上问题 。

特意回来再记录一下。 

*************************************************************************************

      2.语法问题   

        if语句后只能写bool类型的channel i/o 判断语句例如这样

if <-bools

而不能写 

if <- channel //该channel类型为int

 遇见这种情况应该用select语句去设计代码,写i/o语句

3.依旧是语法问题 ,break只能跳出case中的循环,如果想跳出协程的循环应该使用return

下面是最后写出来的代码仅供参考

package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

func producter(product chan int, bools chan bool) {
	yield := 0
	for {
		select {
		case count := <-product:
			if count > 0 {
				count = count + 5
				fmt.Println("莫亚工厂开始生产汽车,目前老厂汽车存量", count)
				
			} else if count == 0 {
				count = count + 10
				fmt.Printf("莫亚工厂全员开始生产汽车,目前老厂汽车存量%d\n", count)

				yield = yield + 1
				fmt.Println("yield=", yield)
				if yield == 20 {
					fmt.Println("吕志文超级工厂产量不足,工厂开始考虑扩厂,新厂房建设中....")
					bools <- true
				}

			}
			product <- count
			
			time.Sleep(1 * time.Second)

		default:
			product <- 1
			fmt.Println("莫亚工厂即将开始生产")
		}
	}
}
func consumer(product chan int, name string, size int, newproduct chan int) {
	allcount := 0
	for {
		select {
		case newcount := <-newproduct:

			count := <-product
			allcount = count + newcount

			if allcount > size {
				allcount = allcount - size
				fmt.Printf("经销商"+name+"购买了%d辆汽车,当前存量%d\n", size, allcount)
				x := rand.Intn(size)
				y := size - x
				
				product <- count - x
				newproduct <- newcount - y

				time.Sleep(10 * time.Second)
			} else if count <= size {
				size = count
				fmt.Printf("经销商"+name+"购买了%d辆汽车,开始缺货\n", size)

				product <- 0
				newproduct <- 0
				time.Sleep(10 * time.Second)
			}

		default:
			count := <-product

			if count > size {
				count = count - size
				fmt.Printf("经销商"+name+"购买了%d辆汽车,当前存量%d\n", size, count)
			} else if count <= size {
				size = count
				fmt.Printf("经销商"+name+"购买了%d辆汽车,开始缺货\n", size)
				count = 0
			}
			
			product <- count
            time.Sleep(10 * time.Second)
		}

	}

}
func newproducter(newproduct chan int, newbools chan bool) {
	newyield := 0
	for {
		select {
		case newcount := <-newproduct:

			if newcount > 0 {
				newcount = newcount + 5
				fmt.Println("莫亚新工厂开始生产汽车,目前新厂汽车存量", newcount)
				newproduct <- newcount
				time.Sleep(1 * time.Second)
			} else if newcount == 0 {
				newcount = newcount + 5
				fmt.Println("莫亚新工厂开始生产汽车,目前新厂汽车存量", newcount)
				newproduct <- newcount
				time.Sleep(1 * time.Second)
				newyield++
				if newyield == 2 {
					fmt.Println("莫亚两个厂产量依旧足,考虑再扩厂或者研发新生产技术....")
					newbools <- true
				}
			}

		default:
			newproduct <- 1
			fmt.Println("新厂建设完毕,正式投入生产")
			//time.Sleep(1 * time.Second)

		}

	}

}

func main() {
	product := make(chan int, 20)
	bools := make(chan bool)
	newproduct := make(chan int, 20)
	newbools := make(chan bool)

	go producter(product, bools)

	time.Sleep(10 * time.Second) //先让工厂生产10s
	for i := 1; i < 10; i++ {
		go consumer(product, strconv.Itoa(i), rand.Intn(10)+5, newproduct)
		//每个客户分批次拿货
		time.Sleep(1 * time.Second)
	}
	for {
		if <-bools {
			break
		}
	}
	go newproducter(newproduct, newbools)
	for {
		if <-newbools {
			break
		}

	}

}