一.GO并发编程综合应用
1.生产者消费者模式
1.1需求分析
生产者每秒生产一个商品,并通过物流公司取货
物流公司将商品运输到商铺
消费者阻塞等待商铺到货,需要消费10次商品
1.2实现原理
1.3代码实现:
package main
import (
"fmt"
"strconv"
"time"
)
func main() {
storageChan := make(chan Product, 10)
shopChan := make(chan Product, 10)
exitChan := make(chan bool, 1)
for i := 1; i < 9; i++ {
go Producer(storageChan, 10)
}
go Logistics(storageChan, shopChan)
go Consumer(shopChan, 10, exitChan)
if <-exitChan {
return
}
}
// Product 商品
type Product struct {
Name string
}
// Producer 生产者
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
}
}
}
// Logistics 物流公司
func Logistics(storageChan <-chan Product, shopChan chan<- Product) {
for {
product := <-storageChan
shopChan <- product
fmt.Println("运输了", product)
}
}
// Consumer 消费者
func Consumer(shopChan <-chan Product, count int, exitChan chan<- bool) {
for {
product := <-shopChan
fmt.Println("消费了", product)
count--
if count < 1 {
exitChan <- true
return
}
}
}
2.协程管道定时任务的应用
2.1需求分析
1.定时执行某个任务,类似延时消息队列
2.或者周期性的执行某个任务,类似定期同步某些数据
2.2实现原理
2.3代码实现:
package main
import (
"fmt"
"time"
)
func main() {
//方式1:
fmt.Println("当前时间:", time.Now())
//timer := time.NewTimer(time.Second * 3)
//t := <-timer.C //timer.C一个只读的管道
//fmt.Println(t)
//方式二:
t := <-time.After(time.Second * 3) //源码可见,实际上NewTimer(d).C
fmt.Println(t)
}
3.定时器的终止与重置
NewTimer, Stop, Reset
package main
import (
"fmt"
"math/rand"
"time"
)
var flag bool = isStopTimer()
func main() {
//方式1:
fmt.Println("当前时间:", time.Now())
timer := time.NewTimer(time.Second * 3)
if flag {
timer.Stop() //如果停止了timer,还去拿fatal error: all goroutines are asleep - deadlock!
} else {
t := <-timer.C //timer.C一个只读的管道
fmt.Println(t)
}
}
func isStopTimer() bool {
rand.Seed(time.Now().UnixNano())
tempInt := rand.Intn(2) + 18
if tempInt >= 18 {
fmt.Println("已经找到了大于18,结束timer")
return true
} else {
return false
}
}
func isResetTimer() int {
rand.Seed(time.Now().UnixNano())
tempInt := rand.Intn(4) + 19
fmt.Println("已经找到",tempInt)
return tempInt-18
}
4.需要每隔时间触发任务
4.1实现原理:
4.2代码实现
package main
import (
"fmt"
"time"
)
func main() {
var count int = 0
ticker := time.NewTimer(time.Second * 1)
go func() {
for {
t := <-ticker.C
fmt.Println("时间:", t.Format("2006-01-02 03:04:05PM"))
count++
if count > 2 {
ticker.Stop()
}
}
}()
time.Sleep(time.Second * 10)
fmt.Println("游戏结束")
}
4.3改造成任务队列
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var count int = 0
var wg sync.WaitGroup
wg.Add(1)
ticker := time.NewTicker(time.Second * 1)
go func() {
defer wg.Done()
defer ticker.Stop()
for {
t := <-ticker.C
fmt.Println("时间:", t.Format("2006-01-02 03:04:05PM"))
count++
if count > 2 {
return
}
}
}()
wg.Wait()
fmt.Println("游戏结束")
}