协程和管道的配合使用

package main

import (
   "fmt"
   "time"
)

var amount = 5                           // 一共需要生产多少个产品
var produceChan = make(chan int, amount) // 生产管道
var sellOutChan = make(chan int, 1)      // 标记是否售罄管道

func produce() {
   // 开始生产产品,共需要生产amount个
   for i := 1; i <= amount; i++ {
      produceChan <- i // 向生产管道发送数据
      fmt.Printf("第%+v个产品已生产 \n", i)
      time.Sleep(time.Millisecond * 500) // 生产完一个产品后休眠一段时间
   }

   // 已生产完amount个产品,可以关闭管道
   close(produceChan)
   fmt.Printf("生产:生产已完成 \n")
}

func sell() {
   // 开始销售产品,这里无需知道amount的值,生产多少就卖多少,直到停止生产
   for {
      i, success := <-produceChan // 从生产管道接收数据
      if !success {
         break
      }
      fmt.Printf("第%+v个产品已卖出 \n", i)
   }

   // 标记产品已售罄,并关闭该管道
   sellOutChan <- 1
   close(sellOutChan)
   fmt.Printf("销售:产品已售罄 \n")
}

func main() {
   // 开启两个协程,一个生产一个销售,生产和销售互不干扰,但又有所关联(必须生产了才能销售)
   go produce() // 生产协程
   go sell()    // 销售协程

   // 开启一个死循环检查产品是否已售罄
   for {
      _, success := <-sellOutChan
      if !success {
         fmt.Printf("即将break死循环,完成main()函数 \n")
         break
      }
   }

   //========== 输出过程·开始 ==========//
   // 第1个产品已生产
   // 第1个产品已卖出
   // 第2个产品已生产
   // 第2个产品已卖出
   // 第3个产品已生产
   // 第3个产品已卖出
   // 第4个产品已生产
   // 第4个产品已卖出
   // 第5个产品已生产
   // 第5个产品已卖出
   // 生产:生产已完成
   // 销售:产品已售罄
   // 即将break死循环,完成main()函数
   //========== 输出过程·结束 ==========//
}

//========== 总结 ==========//
// 1、管道对于协程是线程安全的,不会发生资源竞争的问题,故生产完一个产品虽然会休眠一段时间,但并不受影响销售,因为是生产完
//    一个产品之后销售才能拿到产品去卖,并且是先生产的先销售。
// 2、管道应该由数据发送方来关闭,即谁向管道发送数据,就由谁来关闭这个管道。

Copyright © 2024 码农人生. All Rights Reserved