每日一抄 Go语言使用select切换协程

看了两篇博客,一个说:在任何一个 case 中执行 break 或者 return,select 就结束了。
另一个说:break只能跳出select中的一个case
验证了一下,不知道对不对,感觉是跳出了整个select

func main() {
	v := make(chan int)
	o := make(chan bool)

	select {
	case d := <-v:
		fmt.Println("ddd", d)
	case <-time.After(time.Second * 5):
		fmt.Println("timeout")
		//o <- true
		break
	}
	fmt.Println("ssssssssssssss")

	time.Sleep(time.Second * 100)
	<-o

	fmt.Println("程序结束")
}
package main

import (
	"fmt"
	"time"
)

/*
1.监听的case中,没有满足条件的就阻塞
2.多个满足的条件就任选一个执行
3.select本身不带循环,需要外层的for循环
4.default通常不用,会产生忙轮训
5.break只能跳出select中的一个case

1.加入了默认分支,那么无论涉及通道操作的表达式是否有阻塞,select语句都不会被阻塞。如果那几个表达式都阻塞了,或者说都没有满足求值的条件,那么默认分支就会被选中并执行。

2.如果没有加入默认分支,那么一旦所有的case表达式都没有满足求值条件,那么select语句就会被阻塞。直到至少有一个case表达式满足条件为止。
如果select语句发现同时有多个候选分支满足选择条件,那么它就会用一种伪随机的算法在这些分支中选择一个并执行。注意,即使select语句是在被唤醒时发现的这种情况,也会这样做
*/

/*
go里面提供了一个关键字select,通过select可以监听channel上的数据流动

select的用法与switch语言非常类似,由select开始一个新的选择块,每个选择块条件由case语句来描述

与switch语句可以选择任何可使用相等比较的条件相比,select有比较多的限制,其中最大的一条限制就是每个case语句里必须是一个IO操作
for{
	select {
	case <- chan1:
		//
	case <- chan2:
		//
	default:
		//case表达式都没有满足求值条件,
	}
}
*/

/*
在一个select语句中,go语言会按顺序从头到尾评估每一个发送和接收的语句

如果其中的任意一语句可以继续执行(即没有被阻塞),那么就从哪些可以执行的语句中任意选择一条来使用

如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有两种可能的情况:

如果给出了default语句,那么就会执行default语句,同时程序的执行会从select语句后的语句中恢复
如果没有default语句,那么select语句将被阻塞,直到至少有一个通信可以进行下去
*/

/*
防止channel超时机制
有时候会出现协程阻塞的情况,那么我们如何避免这个情况?我们可以使用select来设置超时
*/

//func main() {
//	v := make(chan int)
//	o := make(chan bool)
//
//	select {
//	case d := <-v:
//		fmt.Println("ddd", d)
//	case <-time.After(time.Second * 5):
//		fmt.Println("timeout")
//		//o <- true
//		break
//	}
//	fmt.Println("ssssssssssssss")
//
//	time.Sleep(time.Second * 100)
//	<-o
//
//	fmt.Println("程序结束")
//}

//超时这种写法也常常用来设置定时执行某段函数
//go func() {
//	select {
//	case <- time.After(5 * time.Second):
//		dosomething()
//	}
//}

/*
default 语句是可选的;fallthrough 行为,和普通的 switch 相似,是不允许的。在任何一个 case 中执行 break 或者 return,select 就结束了。

select 做的就是:选择处理列出的多个通信情况中的一个。

如果都阻塞了,会等待直到其中一个可以处理
如果多个可以处理,随机选择一个
如果没有通道操作可以处理并且写了default 语句,它就会执行:default 永远是可运行的(这就是准备好了,可以执行)。
在 select 中使用发送操作并且有 default 可以确保发送不被阻塞!如果没有 default,select 就会一直阻塞。

select 语句实现了一种监听模式,通常用在(无限)循环中;在某种情况下,通过 break 语句使循环退出。

*/

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go pump1(ch1)
	go pump2(ch2)
	go suck(ch1, ch2)
	time.Sleep(1e9)

}

func pump1(ch chan int) {
	for i := 0; ; i++ {
		ch <- i * 2
	}
}

func pump2(ch chan int) {
	for i := 0; ; i++ {
		ch <- i + 5
	}
}

func suck(ch1, ch2 chan int) {
	for {
		select {
		case v := <-ch1:
			fmt.Printf("Received on channel 1: %d\n", v)
		case u := <-ch2:
			fmt.Printf("Received on channel 2: %d\n", u)
		}
	}
}

/*
在程序 goroutine_select.go 中有 2 个通道 ch1 和 ch2,三个协程 pump1()、pump2() 和 suck()。
这是一个典型的生产者消费者模式。
在无限循环中,ch1 和 ch2 通过 pump1() 和 pump2() 填充整数;
suck() 也是在无限循环中轮询输入的,
通过 select 语句获取 ch1 和 ch2 的整数并输出。
选择哪一个 case 取决于哪一个通道收到了信息。程序在 main 执行 1 秒后结束。

-----------------------------------
©著作权归作者所有:来自51CTO博客作者宇宙之一粟的原创作品,请联系作者获取转载授权,否则将追究法律责任
Go 语言入门很简单:使用 select 切换协程
https://blog.51cto.com/yuzhou1su/5416579
*/
posted @   蹇爱黄  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
点击右上角即可分享
微信分享提示