写在最前面

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实现原理剖析的更多相关文章

  1. select用法&原理详解(源码剖析)(转)

    今天遇到了在select()前后fd_set的变化问题,查了好久终于找到一个有用的帖子了,很赞,很详细!!原文链接如下: select用法&原理详解(源码剖析) 我的问题是: 如下图示:在se ...

  2. NameNode和SecondaryNameNode工作原理剖析

    NameNode和SecondaryNameNode工作原理剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.NameNode中的元数据是存储在那里的? 1>.首先,我 ...

  3. 原理剖析-Netty之服务端启动工作原理分析(下)

    一.大致介绍 1.由于篇幅过长难以发布,所以本章节接着上一节来的,上一章节为[原理剖析(第 010 篇)Netty之服务端启动工作原理分析(上)]: 2.那么本章节就继续分析Netty的服务端启动,分 ...

  4. 46、Spark SQL工作原理剖析以及性能优化

    一.工作原理剖析 1.图解 二.性能优化 1.设置Shuffle过程中的并行度:spark.sql.shuffle.partitions(SQLContext.setConf()) 2.在Hive数据 ...

  5. Dubbo原理剖析 之 @DubboReference.version设置为*

    原文链接 Dubbo原理剖析 之 @DubboReference.version设置为* 1 背景 Dubbo在消费端提供了一个功能,即将消费者的版本号指定为*,那么不管服务端的接口版本是啥,都可以调 ...

  6. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...

  7. ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行

    ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...

  8. 【转】Select模型原理

    Select模型原理利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据,被迫 ...

  9. Select模型原理

    Select模型原理 利用select函数,推断套接字上是否存在数据,或者是否能向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据, ...

随机推荐

  1. $().attr() 和 $().css的区别

    使用jquery的.attr( )方法去给div隐藏,这样写的 $("#div_id").attr("display","none"),发现 ...

  2. PAT 甲级 1053 Path of Equal Weight (30 分)(dfs,vector内元素排序,有一小坑点)

    1053 Path of Equal Weight (30 分)   Given a non-empty tree with root R, and with weight W​i​​ assigne ...

  3. 导出 VuePress构建的网站为 PDF

    前言 学 Rust 也有一段时间了,网上也有不少官方文档的中文翻译版,但是似乎只有 Rust中文网站 文档一直是最新的,奈何并没有 PDF 供直接下载,是在是不太方便,为了方便阅读以及方便后续文档更新 ...

  4. Django:reverse反转URL并传递参数

    需求: 假设在文章详情页评论文章后需要重新刷新显示该页面(原始方法,提交评论表单为form方式,未采用ajax方式), 提交评论后代码会走comment的视图函数,等数据入库之后需要将页面重新定位到文 ...

  5. SQL Server数据同步交换

    一.为了解决数据同步汇聚,数据分发,数据转换,数据维护等需求,TreeSoft将复杂的网状的同步链路变成了星型数据链路.     TreeSoft作为中间传输载体负责连接各种数据源,为各种异构数据库之 ...

  6. 接着上次的python爬虫,今天进阶一哈,局部解析爬取网页数据

    *解析网页数据的仓库 用Beatifulsoup基于lxml包lxml包基于html和xml的标记语言的解析包.可以去解析网页的内容,把我们想要的提取出来. 第一步.导入两个包,项目中必须包含beau ...

  7. C#中使用HttpClient来Post数据的内容HttpContent的各种格式

    平时使用各种网络传输的时候基本上是以Json格式进行的, 所以对其他几种格式也是一知半解, 今天静下心对其好好梳理一番. 首先我借鉴了一篇文章(https://segmentfault.com/a/1 ...

  8. 27.Spark中transformation的介绍

    Spark支持两种RDD操作:transformation和action.transformation操作会针对已有的RDD创建一个新的RDD: 而action则主要是对RDD进行最后的操作,比如遍历 ...

  9. [转帖]当 K8s 集群达到万级规模,阿里巴巴如何解决系统各组件性能问题?

    改天学习一下. https://www.cnblogs.com/alisystemsoftware/p/11570806.html   当 K8s 集群达到万级规模,阿里巴巴如何解决系统各组件性能问题 ...

  10. oracle管道函数的用法(一行拆为多行)

    oracle管道函数是一类特殊的函数,oracle管道函数返回值类型必须为集合 如果需要在客户端实时的输出函数执行过程中的一些信息,在oracle9i以后可以使用管道函数(pipeline funct ...