个人免费网站开发珠海科技网站建设

当前位置: 首页 > news >正文

个人免费网站开发,珠海科技网站建设,在线商标设计,新媒体营销思维概述 这里又有多路复用#xff0c;但是Go中的这个多路复用不同于网络中的多路复用。在Go里#xff0c;select用于同时等待多个通信操作#xff08;即多个channel的发送或接收操作#xff09;。Go中的channel可以参考我的文章#xff1a;逐步学习Go-并发通道chan(channel)…概述 这里又有多路复用但是Go中的这个多路复用不同于网络中的多路复用。在Go里select用于同时等待多个通信操作即多个channel的发送或接收操作。Go中的channel可以参考我的文章逐步学习Go-并发通道chan(channel) 拆字解释 多路指的是多个channel操作路径。你可以在select块中定义多个case每个case对应一个channel上的I/O操作发送或接收。 复用指的是select的功能它可以监听多个channel上的事件并且仅当其中一个channel准备就绪时才会执行相关操作。这样单个goroutine可以高效地等待多个并发事件而不是单个事件。
复用的是goroutine一个goroutine使用select可以监听多个信道。 整体来讲Select就是为channel设计的。 select语法 Go语言中的select关键字功能在概念上与操作系统的select类似区别在于Go的select是用于goroutine监听多个channel的可读或可写状态。 Go的select允许在channel上进行非阻塞收发同时当多个channel同时响应时select会随机执行其中的一个case。 Go的select语句可以包含一个default分支使得在没有channel准备好时不会阻塞goroutine而是执行default分支。 select {case -ch:println(recieved)case -time.After(10 * time.Second):println(Timeout)default:printStr Hello Select}COPY 接下来我们来看场景用例。 在下面的场景测试用例中我们定义了三个channel ch1, ch2和ch3。 select只有一个case条件满足 我们创建完成三个channel以后我们只想ch1发送消息那么在select三个channel时只有 case - ch1可以满足用例执行会输出Recieved ch1。 func TestSelect_ShouldRecvChan1_WhenChan1CaseWasFullfilled(t *testing.T) {ch1 : make(chan int, 1)ch2 : make(chan int, 1)ch3 : make(chan int, 1)chans : []chan int{ch1, ch2, ch3}var wg sync.WaitGroupwg.Add(1)go func() {chans[0] - 1wg.Done()}()wg.Wait()select {case -ch1:println(Recieved ch1)case -ch2:println(Recieved ch2)case -ch3:println(Recieved ch3)case -time.After(10 * time.Second):println(Timeout)default:}}COPY select有多个case条件满足 在这个场景中我们使用三个goroutine向三个channel都发送了消息然后等待所有的goroutine执行完成确保3个channel都接收到了消息那么select会随机选择一个case条件执行如果自己测试需要多执行几次因为不止下一次会执行那个case分支。 如果select中的多个case同时满足Go语言如何进行选择。Go语言官方文档规定当多个case都可以运行时Go会按照伪随机的方式来选择一个case执行。这个伪随机是指它不是完全随机的而是通过一定的算法进行选择以防止某个channel在高并发的情况下出现饿死被忽略的情况。 func TestSelect_ShouldRandomEnterCaseBranch_WhenAllChannelsCaseWereFullfilled(t *testing.T) {ch1 : make(chan int, 1)ch2 : make(chan int, 1)ch3 : make(chan int, 1)chans : []chan int{ch1, ch2, ch3}var wg sync.WaitGroupwg.Add(3)for i : 0; i 3; i {go func(i int) {chans[i] - 1wg.Done()}(i)}wg.Wait()select {case -ch1:println(Recieved ch1)case -ch2:println(Recieved ch2)case -ch3:println(Recieved ch3)case -time.After(10 * time.Second):println(Timeout)default:}}COPY select没有条件满足-阻塞Deadlock 在这个场景我们只是创建了3个channel但是没有向三个channel发送消息那么执行select时go会panic, 错误信息为Deadlock。 func TestSelect_ShouldBlock_WhenNoCaseWasFullfilled(t *testing.T) {ch1 : make(chan int, 1)ch2 : make(chan int, 1)ch3 : make(chan int, 1)select {case -ch1:println(Recieved ch1)case -ch2:println(Recieved ch2)case -ch3:println(Recieved ch3)}}COPY select没有条件满足-超时 在这个场景中我们创建了三个channel然后没有向这三个channel中发送消息最后我们使用select尝试从三个channel中接收消息但是我们在case中增加了一个超时检测。 在这个场景中select会在10秒后执行 case -time.After(10 * time.Second):分支因为管道条件没有被满足且没有default。 func TestSelect_ShouldTimeout_WhenNoCaseWasFullfilled(t *testing.T) {ch1 : make(chan int, 1)ch2 : make(chan int, 1)ch3 : make(chan int, 1)select {case -ch1:println(Recieved ch1)case -ch2:println(Recieved ch2)case -ch3:println(Recieved ch3)case -time.After(10 * time.Second):println(Timeout)}}COPY select没有条件满足-default 在这个场景中代码和上面的差别在于我们添加了default分支添加了default后如果所有case没有条件满足则执行default分支所以你执行这个用例控制台会打印Default。 func TestSelect_ShouldRunDefaultBranch_WhenNoCaseWasFullfilledAndHasDefaultBranch(t *testing.T) {ch1 : make(chan int, 1)ch2 : make(chan int, 1)ch3 : make(chan int, 1)select {case -ch1:println(Recieved ch1)case -ch2:println(Recieved ch2)case -ch3:println(Recieved ch3)case -time.After(10 * time.Second):println(Timeout)default:println(Default)}}COPY select关闭的channel接收 在这个场景中我们创建3个channel然后理解关闭最后使用select来读取三个channel那么根据关闭后chnanel的定义channel在关闭后永远都可以读取那么select 的case条件可以被满足且随机选择一个case分支执行只是读取到的都是“0”值。 注意0值这个是根据不同类型而不一样的而且go是严格类型检查,nil是不通用的 func TestSelect_ShouldRecvZeroValue_WhenSelectFromClosedChannel(t *testing.T) {ch1 : make(chan int, 1)ch2 : make(chan int, 1)ch3 : make(chan int, 1)close(ch1)close(ch2)close(ch3)select {case value : -ch1:if value 0 {println(Recieved zero value from ch1)} else {println(Recieved ch1)}case value : -ch2:if value 0 {println(Recieved zero value from ch2)} else {println(Recieved ch2)}case value : -ch3:if value 0 {println(Recieved zero value from ch3)} else {println(Recieved ch3)}case -time.After(10 * time.Second):println(Timeout)default:println(Default)} }COPY select 在关闭的channel上发送 在这个场景中我们向通过select的case分支来向关闭的channel发送数据根据go channel的定义会发生panic。 如下截图我们的UT显示PASS表示发生了Panic,当然你也可以改变一下把assert.Panics注释掉直接执行select的那么你会得到第二张图的结果send on closed channel func TestSelect_ShouldPanic_WhenSendToClosedChannel(t *testing.T) {ch1 : make(chan int, 1)ch2 : make(chan int, 1)ch3 : make(chan int, 1)close(ch1)close(ch2)close(ch3)assert.Panics(t, func() {select {case ch1 - 1:println(send ch1)case ch2 - 1:println(send ch2)case ch3 - 1:println(send ch3)case -time.After(10 * time.Second):println(Timeout)default:println(Default)}})} 参考 逐步学习Go-Select多路复用 – FOF编程网