golang中select语句的简单实例
作者:燕双鹰... 发布时间:2023-09-03 03:01:28
前言
在golang语言中,select语句 就是用来监听和channel有关的IO操作,当IO操作发生时,触发相应的case动作。有了 select语句,可以实现 main主线程 与 goroutine线程 之间的互动。
select {
case <-ch1 : // 检测有没有数据可读
// 一旦成功读取到数据,则进行该case处理语句
case ch2 <- 1 : // 检测有没有数据可写
// 一旦成功向ch2写入数据,则进行该case处理语句
default:
// 如果以上都没有符合条件,那么进入default处理流程
}
注意事项:
select语句 只能用于channel信道的IO操作,每个case都必须是一个信道。
如果不设置 default条件,当没有IO操作发生时,select语句就会一直阻塞;
如果有一个或多个IO操作发生时,Go运行时会随机选择一个case执行,但此时将无法保证执行顺序;
对于case语句,如果存在信道值为nil的读写操作,则该分支将被忽略,可以理解为相当于从select语句中删除了这个case;
对于空的 select语句,会引起死锁;
对于在 for中的select语句,不能添加 default,否则会引起cpu占用过高的问题;
1.先举个简单例子
先创建两个信道,并在 select 前往 c2 发送数据
package main
import (
"fmt"
)
//go的通道选择器 让你可以同时等待多个通道操作。go协程和通道以及选择器的结合是go的一个强大特性。
func main() {
// 在我们的例子中,我们将从两个通道中选择。
c1 := make(chan string, 1)
c2 := make(chan string, 1)
c2 <- "nihao"
//go func() {
//time.Sleep(time.Second * 1)
//c1 <- "one"
//}()
//
//go func() {
//time.Sleep(time.Second * 2)
//c2 <- "two"
//}()
//我们使用 `select` 关键字来同时等待这两个值,并打印各自接收到的值。
//for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
default:
fmt.Println("No data received")
}
//}
}
在运行 select 时,会遍历所有(如果有机会的话)的 case 表达式,只要有一个信道有接收到数据,那么 select 就结束,所以输出如下
2. 避免造成死锁
select 在执行过程中,必须命中其中的某一分支。
如果在遍历完所有的 case 后,若没有命中(命中:也许这样描述不太准确,我本意是想说可以执行信道的操作语句)任何一个 case 表达式,就会进入 default 里的代码分支。
package main
import (
"fmt"
)
//go的通道选择器 让你可以同时等待多个通道操作。go协程和通道以及选择器的结合是go的一个强大特性。
func main() {
// 在我们的例子中,我们将从两个通道中选择。
c1 := make(chan string, 1)
c2 := make(chan string, 1)
//c2 <- "nihao"
//go func() {
//time.Sleep(time.Second * 1)
//c1 <- "one"
//}()
//
//go func() {
//time.Sleep(time.Second * 2)
//c2 <- "two"
//}()
//我们使用 `select` 关键字来同时等待这两个值,并打印各自接收到的值。
//for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
//default:
//fmt.Println("No data received")
//}
}
}
但如果你没有写 default 分支,select 就会阻塞,直到有某个 case 可以命中,而如果一直没有命中,select 就会抛出 deadlock
的错误,就像下面这样子。
1.解决这个问题的方法有两种
一个是,养成好习惯,在 select 的时候,也写好 default 分支代码,尽管你 default 下没有写任何代码。
另一个是,让其中某一个信道可以接收到数据
3. select 随机性
之前学过 switch 的时候,知道了 switch 里的 case 是顺序执行的,但在 select 里却不是。
通过下面这个例子的执行结果就可以看出
4. select 的超时
当 case 里的信道始终没有接收到数据时,而且也没有 default 语句时,select 整体就会阻塞,但是有时我们并不希望 select 一直阻塞下去,这时候就可以手动设置一个超时时间。
5. 读取/写入都可以
上面例子里的 case,好像都只从信道中读取数据,但实际上,select 里的 case 表达式只要求你是对信道的操作即可,不管你是往信道写入数据,还是从信道读出数据。
6. 总结一下
select 与 switch 原理很相似,但它的使用场景更特殊,学习了本篇文章,你需要知道如下几点区别:
select 只能用于 channel 的操作(写入/读出),而 switch 则更通用一些;
select 的 case 是随机的,而 switch 里的 case 是顺序执行;
select 要注意避免出现死锁,同时也可以自行实现超时机制;
select 里没有类似 switch 里的 fallthrough 的用法;
select 不能像 switch 一样接函数或其他表达式。
来源:https://blog.csdn.net/anzhenxi3529/article/details/123644425


猜你喜欢
- 一、selenium截取验证码import jsonfrom io import BytesIOimport timefrom test.t
- 一、输入注入注入攻击非常广泛而且很常见,注入有很多种类,它们影响所有的语言、框架和环境。SQL 注入是直接编写 SQL 查询(而非使用 OR
- for 循环本系列前面 “探索 Python,第 5 部分:用 Python 编程” 一文讨论了 if 语句和 while 循环,讨论了复合
- 出图是项目里常见的任务,有的项目甚至会要上百张图片,所以批量出土工具很有必要。arcpy.mapping就是ArcGIS里的出图模块,能快速
- 前言在本文中,我们将设计一个可以执行算术运算的解释器。我们不会重新造轮子。文章将使用由 David M. Beazley 开发的词法解析器
- ASP实例代码,利用SQL语句动态创建Access表。留作参考,对在线升级数据库有用处.<% nowtime = now()
- 背景描述:Pycharm作为python专业开发工具,要比轻量级的vscode更加稳定,适合个人、团队的项目开发。同时pycharm来创建虚
- 在 Python 中,列表是一种非常常见且强大的数据类型。但有时候,我们需要从一个列表中删除特定元素,尤其是当这个元素出现多次时。本文将介绍
- strIn 为 输入的Email地址字符串变量 返回为true或falsereturn Regex.IsMatch(strIn, @&quo
- 写在前面这篇文章推荐一个由Golang编写的一个命令行工具——Glow,这个CLI工具可以在命令行读
- 现在有一个xml,格式如下: <date> <item> <id> 1 </id> <
- 使用标准库importlib的import_module()函数、django的import_string(),它们都可以动态加载指定的 P
- 一、需求说明当我们写爬虫的时候,经常会遇到json格式的数据,它通常是如下结构:data = [{'name':'小
- 如何侦测HTTP表头信息?可用下列办法侦测并显示所有的HTTP HEADERS:<HTML><HEAD><TI
- 特殊属性Python中对象包括很多双下划綫开始和结束的属性,这些特殊属性,有特殊用法。特殊方法含义obj.__dict__对象的属性字典ob
- Flask是一个轻量级的Web框架。虽然是轻量级的,但是对于组件一个大型的、模块化应用也是能够实现的,“蓝图”就是这样一种实现。对于模块化应
- 目录为什么需要分区?分区的策略分区隐患为什么需要分区?当面对巨大的数据表的时候,至少有一件事情是确定的,表太大了以至于每次查询的时候我们没法
- 一、模块概述模块指的是包含python代码的文件,也就是一个.py文件就是一个模块。文件夹(directory)---->包(pack
- 有一些问题可能会遇到同元素多列去重问题,下面介绍一种非常简单效率也很快的做法,用pandas来实现。首先我们看一下数据类型:G1 G2a b
- 计算字符串中所有数字的和,字符串中有数字和字母组合而成如果出现连续数字,按照一个数操作具体解释在代码行里:def sum_str(str1)