使用Select进行调度

非阻塞式获取

package main

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

func main() {
	var c1, c2 chan int
	for {
		select {
		case n := <-c1:
			fmt.Println("Received from c1:", n)
		case n := <-c2:
			fmt.Println("Received from c2:", n)
		default:
			fmt.Println("Received no value")
		}
	}

}

在这里插入图片描述

使用select+default实现非非阻塞式获取

同时获取两个chan中的消息

package main

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

func main() {
	var c1, c2 chan int = generator(), generator()
	for {
		select {
		case n := <-c1:
			fmt.Println("Received from c1:", n)
		case n := <-c2:
			fmt.Println("Received from c2:", n)
		}
	}

}
func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

在这里插入图片描述
c1和c2打印的速度不一样,谁先出数据就会先选择谁,两个同时出就会随机的去选一个

转发

package main

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

func main() {
	var c1, c2 chan int = generator(), generator()
	w := createWorker(0)
	for {
		select {
		case n := <-c1:
			w <- n
		case n := <-c2:
			w <- n
		}
	}

}
func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func worker(id int, c chan int) {
	for n := range c {
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

在这里插入图片描述
这样同样可以做到我们想要的,但是再Select里面收到数据以后,后面所作的事又会阻塞住

再Select里面进行非阻塞的首发

package main

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

func main() {
	var c1, c2 chan int = generator(), generator()
	var worker = createWorker(0)
	n := 0
	hasValue := false
	for {
		var activeWorker chan<- int
		if hasValue {
			activeWorker = worker
		}
		select {
		case n = <-c1:
			hasValue = true
		case n = <-c2:
			hasValue = true
		case activeWorker <- n:
			hasValue = false
		}
	}

}
func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func worker(id int, c chan int) {
	for n := range c {
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

在这里插入图片描述
现在已经实现了非阻塞式的收发,但是现在还是有问题,如果生成的数据过快,还是会有数据丢失的情况

模拟数据丢失

package main

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

func main() {
	var c1, c2 chan int = generator(), generator()
	var worker = createWorker(0)
	n := 0
	hasValue := false
	for {
		var activeWorker chan<- int
		if hasValue {
			activeWorker = worker
		}
		select {
		case n = <-c1:
			hasValue = true
		case n = <-c2:
			hasValue = true
		case activeWorker <- n:
			hasValue = false
		}
	}

}
func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func worker(id int, c chan int) {
	for n := range c {
		time.Sleep(5 * time.Second)
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

在这里插入图片描述
让activeWorker每五秒收一条数据,消耗速度过慢,中间有些数据是会被跳掉的,会出现数据丢失的情况!

使用slice存放积压的数据

package main

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

func main() {
	var c1, c2 chan int = generator(), generator()
	var worker = createWorker(0)
	var values []int
	for {
		var activeWorker chan<- int
		var activeValue int
		if len(values) > 0 {
			activeWorker = worker
			activeValue = values[0]
		}
		select {
		case n := <-c1:
			values = append(values, n)
		case n := <-c2:
			values = append(values, n)
		case activeWorker <- activeValue:
			values = values[1:]
		}
	}

}
func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func worker(id int, c chan int) {
	for n := range c {
		time.Sleep(5 * time.Second)
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

在这里插入图片描述
我们使用slice存放挤压的数据,然后每五秒消费一条数据;解决了数据丢失的问题,但是现在程序并不会自动退出,会一直死循环下去,而且没办法查看现在挤压了多少条数据;也没办法去查看消息是否超时

程序自动退出&输出挤压数据量&超时提醒

package main

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

func main() {
	var c1, c2 chan int = generator(), generator()
	var worker = createWorker(0)
	var values []int
	// 10秒后接收一条数据
	after := time.After(10 * time.Second)
	// 每秒接到一条数据
	tick := time.Tick(time.Second)
	for {
		var activeWorker chan<- int
		var activeValue int
		if len(values) > 0 {
			activeWorker = worker
			activeValue = values[0]
		}
		select {
		case n := <-c1:
			values = append(values, n)
		case n := <-c2:
			values = append(values, n)
		case activeWorker <- activeValue:
			values = values[1:]
		case <-time.After(500 * time.Millisecond):
			// 每600毫秒没有拿到数据认为超时
			fmt.Println("timeout")
		case <-tick:
			// 每秒输出当前已经挤压了多少条数据
			fmt.Println("queue len = ",len(values))
		case <-after:
			// 接到数据后结束
			fmt.Println("byebye")
			return
		}
	}

}
func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func worker(id int, c chan int) {
	for n := range c {
		time.Sleep(1 * time.Second)
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

在这里插入图片描述

总结

  • Select的使用
  • 定时器的使用
  • 再Select使用Nil chan
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.番茄炒蛋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值