golang的select实现原理剖析
写在最前面
select为golang提供了多路IO复用机制,和其他IO复用一样,用于检测是否有读写事件是否ready。
本文将介绍一下golang的select的用法和实现原理。
实现原理
golang实现select的时候,实际上为每一个case语句定义了一个数据结构,select语句块执行的时候,实际上可以类比成对一个case数组处理的代码块(或者函数),然后程序流程转到选中的case块。
case数据结构
源码包src/runtime/select.go:scase定义了表示case语句的数据结构:
type scase struct {
c *hchan // chan
kind uint16
elem unsafe.Pointer // data element
}
scase.c表示当前case语句操作的chan指针,这也表明一个case只能监听一个chan。
scase.kind表示当前的chan是可读还是可写channel或者是default。三种类型分别由常量定义:
- caseRecv:case语句中尝试读取scase.c中的数据;
- caseSend:case语句中尝试向scase.c中写入数据;
- caseDefault: default语句
scase.elem表示缓冲区地址,跟据scase.kind不同,有不同的用途:
- scase.kind == caseRecv : scase.elem表示读出channel的数据存放地址;
- scase.kind == caseSend : scase.elem表示将要写入channel的数据存放地址;
select实现逻辑
源码包src/runtime/select.go:selectgo()定义了select选择case的函数:
// selectgo implements the select statement.
//
// *sel is on the current goroutine's stack (regardless of any
// escaping in selectgo).
//
// selectgo returns the index of the chosen scase, which matches the
// ordinal position of its respective select{recv,send,default} call.
func selectgo(sel *hselect) int {
}
其中数据结构hselect如下:
// Select statement header.
// Known to compiler.
// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
type hselect struct {
tcase uint16 // total count of scase[]
ncase uint16 // currently filled scase[]
pollorder *uint16 // case poll order
lockorder *uint16 // channel lock order
scase [1]scase // one per case (in order of appearance)
}
hselect.tcase存的是scase总数。
hselect.pollorder是保存scase的随机后的序列。以达到随机检测case的目的。
hselect.lockorder是保存的channel地址。所有case语句中channel序列,以达到去重防止对channel加锁时重复加锁的目的。
selectgo返回int,表示选中的scase,也就是ready的channel index。
该函数执行逻辑大致如下:
1. 锁定scase语句中所有的channel
2. 按照随机顺序检测scase中的channel是否ready
2.1 如果case可读,则读取channel中数据,解锁所有的channel,然后返回(case index)
2.2 如果case可写,则将数据写入channel,解锁所有的channel,然后返回(case index)
2.3 所有case都未ready,则解锁所有的channel,然后返回(default index)
3. 所有case都未ready,且没有default语句
3.1 将当前协程加入到所有channel的等待队列
3.2 当将协程转入阻塞,等待被唤醒
4. 唤醒后返回channel对应的case index
4.1 如果是读操作,解锁所有的channel,然后返回(case index)
4.2 如果是写操作,解锁所有的channel,然后返回(case index)
golang的select实现原理剖析的更多相关文章
- select用法&原理详解(源码剖析)(转)
今天遇到了在select()前后fd_set的变化问题,查了好久终于找到一个有用的帖子了,很赞,很详细!!原文链接如下: select用法&原理详解(源码剖析) 我的问题是: 如下图示:在se ...
- NameNode和SecondaryNameNode工作原理剖析
NameNode和SecondaryNameNode工作原理剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.NameNode中的元数据是存储在那里的? 1>.首先,我 ...
- 原理剖析-Netty之服务端启动工作原理分析(下)
一.大致介绍 1.由于篇幅过长难以发布,所以本章节接着上一节来的,上一章节为[原理剖析(第 010 篇)Netty之服务端启动工作原理分析(上)]: 2.那么本章节就继续分析Netty的服务端启动,分 ...
- 46、Spark SQL工作原理剖析以及性能优化
一.工作原理剖析 1.图解 二.性能优化 1.设置Shuffle过程中的并行度:spark.sql.shuffle.partitions(SQLContext.setConf()) 2.在Hive数据 ...
- Dubbo原理剖析 之 @DubboReference.version设置为*
原文链接 Dubbo原理剖析 之 @DubboReference.version设置为* 1 背景 Dubbo在消费端提供了一个功能,即将消费者的版本号指定为*,那么不管服务端的接口版本是啥,都可以调 ...
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...
- ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行
ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...
- 【转】Select模型原理
Select模型原理利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据,被迫 ...
- Select模型原理
Select模型原理 利用select函数,推断套接字上是否存在数据,或者是否能向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据, ...
随机推荐
- Lombok子类与父类的@Builder注解冲突
解决方法之一:去掉父类的@builder 缺点:父类不能使用Builder构造器模式 来源:https://www.cnblogs.com/lori/p/10266508.html
- delphi中TTreeView的使用方法
[学习万一老师博客摘要] TTreeView 与两个重要的类相关:TTreeNodes.TTreeNode . TTreeNodes即是TTreeView 的Items属性,TTreeNodes是TT ...
- rm -rf 误删后该怎么办?
Google有一个开源的包 叫ext3grep工具他可以回复删除的文件,甚至是drop database,想什么呢,数据库啦!这个工具需要在ext3或者ext4 的文件系统上才可以实现,因为ext3文 ...
- c#webservice的简单示例
webservice.就概念上来说,可能比较复杂,不过我们可以有个宏观的了解:webservice就是个对外的接口,里面有 函数可供外部客户调用(注意:里面同样有客户不可调用的函数).假若我们是服务端 ...
- maven执行过程中抛出的各类异常信息
价值 各类异常信息分类 举例 maven源代码的模块maven-core里的各类*Exception命名的class包含里,maven执行过程中打印的各类异常日志内容 比如如下错误 错误信息分别来自( ...
- 【C#设计模式3】工厂方法模式
一.引言 在简单工厂模式中讲到简单工厂模式的缺点,有一点是——简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样就会造成简单工厂的实现逻辑过于复杂,然而本专题介绍的工厂方法模式可以 ...
- linux下的进程通信之管道与FIFO
概念:管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息. 优点:不需 ...
- mysql 查询结果为null 或 空字符串时,返回指定字符串
直接上代码, 亲测可用: SELECT IF ( ifnull( 字段, '' ) = '', '返回的字符串', 字段) AS 别名(或者不要也可以) FROM table
- tomcat性能优化参数
线上环境使用默认tomcat配置文件,性能很一般,为了满足大量用户的访问,需要对tomcat进行参数性能优化,具体优化的地方如下: Linux内核的优化 服务器资源JVM 配置的优化 Tomcat参数 ...
- Feign【token传递】
使用feign调用服务的时候,存在一个问题,比如当前服务调用A服务,在请求头中包含了某些特殊的字段信息,比如当前操作人的token信息,调用A的时候可以正常拿到token,然而在去调用B服务的时候,可 ...