Golang关键字-select

news2024/11/14 14:12:27

一、Select解决什么问题?

在这里插入图片描述
在Golang中,两个协程之间通信Channel(图一),在接受协程中通过代码表示即为<ch;如果协程需要监听多个Channel,只要有其中一个满足条件,就执行相应的逻辑(图二),这种select的应用场景之一,代码如下:

func TestSelect(t *testing.T) {
    ch1 := make(chan int, 1)
    ch2 := make(chan int , 1)

    select {
        case <-ch1:
        fmt.Println("ch1")
        case <-ch2:
        fmt.Println("ch2")
        default:
        }
}


上述代码,创建两个通道,通过select监听协程是否有数据,如果有打印相应的值,如果没有通过default结束程序运行;

二、Select常用用法

循环阻塞监测

func TestLoopSelect(t *testing.T) {
    ch1 := make(chan int, 1)
    ch2 := make(chan int, 1)

    go func() {
        // 每隔1s发送一条消息到channel中
        for range time.Tick(1 * time.Second) {
            ch1 <- 1
        }
    }()

    for {
        select {
            case <-ch1:
            fmt.Println("ch1")
            case <-ch2:
            fmt.Println("ch2")
        }
    }
}

这种写法特别常见,起一个协程,阻塞循环监听多个channel,如果有数据执行对应的操作。比如说

// go-zero/core/discov/internal/registry.go
func (c *cluster) watchStream(cli EtcdClient, key string, rev int64) bool {
    var rch clientv3.WatchChan
    if rev != 0 {
        rch = cli.Watch(clientv3.WithRequireLeader(c.context(cli)), makeKeyPrefix(key), clientv3.WithPrefix(),
                      clientv3.WithRev(rev+1))
    } else {
        rch = cli.Watch(clientv3.WithRequireLeader(c.context(cli)), makeKeyPrefix(key), clientv3.WithPrefix())
    }

    for {
        select {
            case wresp, ok := <-rch:
        	...
            c.handleWatchEvents(key, wresp.Events)
            case <-c.done:
            return true
        }
    }
}

上述代码,通过for + select阻塞循环监测注册中心数据是否有变换,有变化的话,针对变化类型,执行对应逻辑;

非阻塞监控

func TestSelect(t *testing.T) {
    ch1 := make(chan int, 1)
    ch2 := make(chan int , 1)

    select {
        case <-ch1:
        fmt.Println("ch1")
        case <-ch2:
        fmt.Println("ch2")
        default:
        }
}

这段代码的意思是,程序执行到select,就检查一下channel里面是否有数据,有就处理,没有就退出;在grpc-go中,

// grpc-go/clientconn.go
func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) {
	cc := &ClientConn{
		target: target,
		conns:  make(map[*addrConn]struct{}),
		dopts:  defaultDialOptions(),
		czData: new(channelzData),
	}

	defer func() {
		select {
		case <-ctx.Done():
			switch {
			case ctx.Err() == err:
				conn = nil
			case err == nil || !cc.dopts.returnLastError:
				conn, err = nil, ctx.Err()
			default:
				conn, err = nil, fmt.Errorf("%v: %v", ctx.Err(), err)
			}
		default:
		}
	}()

	if cc.dopts.scChan != nil {
		// Blocking wait for the initial service config.
		select {
		case sc, ok := <-cc.dopts.scChan:
			if ok {
				cc.sc = &sc
				cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{&sc})
			}
		case <-ctx.Done():
			return nil, ctx.Err()
		}
	}

}

上述代码中,有两个地方用到select,一个地方是非阻塞,检查contex是否被取消;另外一个是阻塞等待;

三、select原理

在这里插入图片描述
如果想了解select的实现,可以阅读runtime.selectgo代码。它主要包含三部分:

首先,检查一下是否有准备就绪的channel(多个channel就绪,随机选择一个),如果有,就执行;
其次,将当前goroutine包装成sudog,挂载到对应的channel上;
最后,如果channel中数据准备就绪,唤醒该协程继续执行第一步逻辑;

【注】源码细节,感兴趣并且有需求可以深入了解,但是不要陷入源码的怪圈中;

总结

本文主要讲述下面三部分内容:

从Go源码开发者的角度考虑,为什么需要select?
介绍了select常用的两种写法,一种是非阻塞的,一种是阻塞的,以及开源项目如何使用它们;
介绍了select的基本实现;

参考

Go语言设计与实现
gprc-go
go-zero

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1135523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

尚硅谷Flume(仅有基础)

q 1 概述 1.1 定义 Flume 是Cloudera 提供的一个高可用的&#xff0c;高可靠的&#xff0c;分布式的海量日志采集、聚合和传输的系统。Flume 基于流式架构&#xff0c;灵活简单。 Flume最主要的作用就是&#xff0c;实时读取服务器本地磁盘的数据&#xff0c;将数据写入到HD…

易点易动固定资产管理系统:高效盘点海量固定资产的得力助手

固定资产是企业重要的财务资源之一&#xff0c;盘点是保证固定资产准确性和完整性的关键环节。然而&#xff0c;对于拥有海量固定资产的企业来说&#xff0c;传统的手工盘点方式效率低下且容易出错。为了解决这一难题&#xff0c;易点易动固定资产管理系统应运而生。本文将深入…

AM@第二类换元法积分

文章目录 abstract第一类换元法第二类换元法分析定理&#x1f47a;证明第二类换元公式的应用 倒代换三角恒等化去根式其他使用第二换元法情形例 附加积分公式表例 附 abstract 第二类换元法(简称第二换元法)的原理和应用 第一类换元法 通过变量代换 u ϕ ( x ) u\phi(x) uϕ…

GoLong的学习之路(十)语法之函数

书接上回&#xff0c;上回书说到&#xff0c;结构体&#xff0c;一言之重在于体。一体之重在于经。经之重甚于骨。这张就说go的经络—函数。 文章目录 函数函数如何定义参数可变参数 返回值多返回值 函数类型与变量 高阶函数函数作为参数函数作为返回值匿名函数闭包defer语句底…

虹科 | 解决方案 | 非道路移动机械诊断方案

虹科Pico汽车示波器为卡车、拖拉机、叉车、船只、联合收割机、挖掘机开发了专用的测试附件和软件测试菜单&#xff0c;比如 24 V 电池、Bosch Denoxtronic、J1939 通信、发动机和液压传动系统以及部件测试等。我们为从事重型车辆和非道路移动机械的维护与诊断的朋友&#xff0c…

通用表表达式查询

1.方法&#xff1a; 1.1普通变量创建 with 表名&#xff08;列名&#xff09; as&#xff08;select 内容&#xff09; 语义&#xff1a;创建一张表 列名和内容11对应 和临时表的区别&#xff0c;这个类似变量&#xff0c;变量和常量的区别 后面可以影响前面&#xff1a; 1…

通天之网:卫星互联网与跨境电商的数字化未来

在当今数字化时代&#xff0c;互联网已经成为商业的核心。跨境电商&#xff0c;作为在线商业的一部分&#xff0c;一直在寻求新的途径来拓宽其边界。近年来&#xff0c;卫星互联网技术的发展已经成为这一领域的重要驱动力&#xff0c;不仅将互联网带到了全球各个角落&#xff0…

DSP 开发例程: led_flash

此例程实现在 EVM6678L 开发板控制 LED 闪烁. 使用了 SYS/BIOS 和 MCSDK PDK TMS320CC6678 两个组件. 例程源码可从我的 gitee.com 仓库上克隆或下载. 目录 创建工程源码编辑main.cplatform_osal.capp.cfg 编译调试使用 板载仿真器使用 外部仿真器 创建工程 点击菜单: File | N…

51单片机实验:数码管动态显示00-99

1、实验要求 利用STC89C52RC单片机开发板实现&#xff1a;使用2位数码管循环显示00-99&#xff0c;每次间隔1s&#xff0c;并且当计数到20时&#xff0c;则蜂鸣器鸣响1次。 2、实验分析 程序实现分析&#xff1a; 1、定义数码管位选引脚&#xff08;P2.4、P2.5、P2.6、…

C++ BinarySercahTree for version

搜索二叉树定义 搜索二叉树模拟实现 首先写一个模版&#xff0c;然后写一个搜索二叉树的类 BSTree&#xff0c;类里面给 BSTe进行重命名为&#xff1a;Node。 template<class K> class BSTree {tyepdef BSTree<K> Node; private:Node* root nullptr; };再写一个…

Qt中的枚举变量,Q_ENUM,Q_FLAG以及Qt中自定义结构体、枚举型做信号参数传递

Qt中的枚举变量,Q_ENUM,Q_FLAG,Q_NAMESPACE,Q_ENUM_NS,Q_FLAG_NS以及其他 理论基础&#xff1a;一、Q_ENUM二、QMetaEnum三、Q_FLAG四、示例 Chapter1 Qt中的枚举变量,Q_ENUM,Q_FLAG,Q_NAMESPACE,Q_ENUM_NS,Q_FLAG_NS以及其他前言Q_ENUM的使用Q_FLAG的引入解决什么问题&#xf…

怎么在Python爬虫中使用IP代理以避免反爬虫机制?

在进行网络爬虫的过程中&#xff0c;尤其是在大规模批量抓取数据时&#xff0c;需要应对各种反爬虫技术&#xff0c;其中最常用的就是IP封锁。为了避免IP被封锁&#xff0c;我们可以使用IP代理来隐藏自己的真实IP地址&#xff0c;从而让爬虫活动看起来更像正常的浏览器行为。 I…

Table-GPT:让大语言模型理解表格数据

llm对文本指令非常有用&#xff0c;但是如果我们尝试向模型提供某种文本格式的表格数据和该表格上的问题&#xff0c;LLM更有可能产生不准确的响应。 在这篇文章中&#xff0c;我们将介绍微软发表的一篇研究论文&#xff0c;“Table-GPT: Table- tuning GPT for Diverse Table…

虹科 | 解决方案 | 汽车示波器 远程诊断方案

车厂总部专家实时指导你修车 当一线汽修技师遇到疑难问题无从下手时&#xff0c;可以准备好pico汽车示波器套装&#xff0c;并戴上我们的M400智能AR眼镜&#xff0c;通过语音操作&#xff0c;呼叫主机厂的技术支持老师&#xff1b;老师通过AR眼镜上的摄像头老师可以实时看到现…

Python数据挖掘:入门、进阶与实用案例分析——基于非侵入式负荷检测与分解的电力数据挖掘

文章目录 摘要01 案例背景02 分析目标03 分析过程04 数据准备05 属性构造06 模型训练07 性能度量08 推荐阅读赠书活动 摘要 本案例将根据已收集到的电力数据&#xff0c;深度挖掘各电力设备的电流、电压和功率等情况&#xff0c;分析各电力设备的实际用电量&#xff0c;进而为电…

财务RPA机器人真的能提高效率吗?

财务部门作为一个公司的管理职能部门承担着一个公司在商业活动中各个方面的重要职责。理论上来说&#xff0c;一个公司的财务部门的实际工作包含但不限于对企业的盈亏情况进行评估、对风险进行预测、通过数据分析把握好公司的财务状况、税务管理等。 然而&#xff0c;实际上在…

分析主题帆软决策报表控件实现点击查询按钮后才能查询

点击「我的分析」即进入分析主题的管理界面&#xff0c;如下图所示&#xff1a; 2.1.1 分析列表区域 「分析列表」存放着当前用户创建的和其他用户协作给该用户的所有分析主题。 可以对分析列表和分析主题进行管理&#xff0c;详情参见&#xff1a;管理我的分析、管理分析主…

oa系统是什么?有哪些功能和作用?

本文将为大家讲解&#xff1a;1、oa系统是什么&#xff1f;有哪些功能和作用&#xff1f; 一、什么是OA系统 OA系统全称为Office Automation&#xff0c;即办公自动化系统。它是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台&#xff0c;具有信息管理、流程管…

微信小程序实现文章内容详情

方案一、使用微信小程序官方提供的webview 前提已经在微信公众平台开发管理配置好了安全域名即&#xff1a; 方案二、把网页转成pdf直接展示 前提已经在微信公众平台开发管理配置好了安全域名即&#xff1a; 实现思路是发起网络请求拿到pdf下载地址&#xff0c;然后wx.download…

Linux (KDE) 中使用Network Settings设置静态ip

在 Linux (KDE) 中使用 Network Settings 设置s5静态IP详细教程 。 首先&#xff0c;打开 KDE 的设置面板。可以通过点击桌面上的设置图标&#xff0c;或者在开始菜单中搜索 “Settings” 并打开。 在设置面板中&#xff0c;点击 “Network” 选项。 接下来&#xff0c;你会看…