golang并发编程案例

 本文主要学习了生产者和消费者模式协程管道定时任务的应用WaitGroup并发控制原理以及底层源码解读

目录

案例一:生产者和消费者模式

案例二:协程管道定时任务的应用

定时器的终止与重置

新的需求:需要每隔固定时间就触发任务

改造成任务队列(任务队列)

WaitGroup并发控制原理以及底层源码解读


案例一:生产者和消费者模式

 

需求分析:

(模式介绍)

        生产者每秒生产一个商品,并通知物流公司取货

        物流公司将商品运输到商铺

        消费者阻塞等待商铺到货 需要消耗10次商品

实验原理:

代码实现:

func main() {

storageChan := make(chan Product,1000)

shopChan := make(chan Product,1000)

exitChan := make(chan bool,1000)



for i:=1 ; i<999 ; i++ {

go Producer(storageChan,1000)

}

go Logistics(storageChan,shopChan)

go Consumer(shopChan,exitChan,1000)

if <-exitChan {

fmt.Println("exit")

return

}

}



//商品

type Product struct {

Name string

}



//生产者

func Producer(storageChan chan Product, count int) {

for {

producer := Product{"商品:" + strconv.Itoa(count)}

storageChan <- producer

count--

time.Sleep(time.Second)

fmt.Println("生产了",producer)

if count < 1 {

return

}

}

}



//物流公司

func Logistics(storageChan <-chan Product,shopChan chan<- Product) {

for {

Product := <- storageChan

shopChan <- Product

fmt.Println("运输了",Product)

}

}



//消费者

func Consumer (shopChan <-chan Product , exitChan chan<- bool , count int ) {

for {

Product := <- shopChan

fmt.Println("消费了",Product)

count--

if count < 1 {

exitChan <- true

return

}

}

}

 

案例二:协程管道定时任务的应用

需求分析:

  1. 定时执行某个任务,类似 延时消息队列{抢购订单支付&未支付(30分钟后看是否支付)}
  2. 或者周期性的执行某个任务,类似定期同步某些数据

实现原理:

 

实现代码:

fmt.Println("当前时间",time.Now())
	//方式1
	timer := time.NewTimer(time.Second * 3)
	t := <-timer.C   //time.C是只读管道

	//方式2
	t := <-time.After(time.Second*3)    //源码可见 实际上返回的就是NewTimer(d).C
	fmt.Println(t)

 

 思考:如果提前完成定时处理的业务,或者需要调整时间。怎么办?

定时器的终止与重置

NewTimer  Stop  Reset

根据一些随机数模拟关闭和重置

代码:

var flag bool = isStopTimer()

func main() {
	fmt.Println("当前时间", time.Now())
	timer := time.NewTimer(time.Second * 3)

	if flag {
		timer.Stop() //如果停止还去拿,则报错fatal error: all goroutines are asleep - deadlock!
	} else {
		t := <-timer.C //time.C是只读管道
		fmt.Println(t)
	}
}

func isStopTimer() bool {
	rand.Seed(time.Now().UnixNano())    
//time.Now().UnixNano()当前时间戳,目的是每次运行时得到的随机数均不相同
	tempInt := rand.Intn(2) + 18
	if tempInt >= 18 {
		fmt.Println("已经找到大于18,技术timer", tempInt)
		return true
	} else {
		return false
	}
}

新的需求:需要每隔固定时间就触发任务

实现原理:

 

ticker只要定义完成,从此刻开始计时,不需要任何其他的操作,每隔固定时间都会触发。

timer定时器,是到固定时间后会执行一次

代码:

var exitChan chan bool
func main() {
	var	count int = 0
	exitChan = make(chan bool,1)
	ticker := time.NewTicker(time.Second*1)
	go func (){     //匿名函数
			for {
			t := <-ticker.C
			fmt.Println("时间:",t.Format("2006-01-02 03:04:05PM"))
			count++
			if count > 5 {
				exitChan <- true
				return
			}
		}
	}()    //后面的括号用于调用
	// time.Sleep(time.Second *10)
	if <-exitChan {
		fmt.Println("游戏结束")
	}
}

改造成任务队列(任务队列

sync包的WaitGroup实现了一个类似任务队列的结构。

可以向队列中加入任务,任务完成会移除,Add()  Done()  Wait()

如果全部完成,队列会触发阻塞以阻止程序继续运行。

代码:

	func main() {
	var	count int = 0
	var waitGroup sync.WaitGroup
	waitGroup.Add(2)   
//括号里面个数取决于下面WaitGroup使用的个数,如果是2那么还等到两个.Done()在执行.Wait()
	ticker := time.NewTicker(time.Second*1)
	go func (){     //匿名函数
		defer waitGroup.Done()
		defer ticker.Stop()
		for {
			t := <-ticker.C
			fmt.Println("时间:",t.Format("2006-01-02 03:04:05PM"))
			count++
			if count > 5 {
				return
			}
		}
	}()    //后面的括号用于调用
	waitGroup.Wait()
	fmt.Println("游戏结束")
}

func (t *Timer) Reset(d Duration) bool

Reset使t重新开始计时,(本方法返回后再)等待时间段d过去后到期。如果调用时t还在等待中会返回真;如果t已经到期或者被停止了会返回假

timer := time.NewTimer(time.Second*1)
	go func (){     //匿名函数
		defer waitGroup.Done()
		defer timer.Stop()
		for {
			t := <-timer.C
			fmt.Println("timer 时间:",t.Format("2006-01-02 03:04:05PM"))
			timer.Reset(time.Second)
			count2++
			if count2 > 3 {
				return
			}
		}
	}()    //后面的括号用于调用

WaitGroup并发控制原理以及底层源码解读

WaitGroup是Golang应用开发过程中经常使用的并发控制技术。

WaitGroup可理解为Wait-Goroutine-Group,即等待一组goroutine结束。比如某个goroutine需要等待其他几个goroutine全部完成,那么使用WaitGroup可以轻松实现。

(.add(2)括号里面个数取决于下面WaitGroup使用的个数,如果是2那么还等到两个.Done()在执行.Wait()

实现原理:

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值