理解channel 工作原理以及源码
- goroutines: 独立执行每个任务,并可能并行执行
- channels: 用于 goroutines 之间的通讯、同步
- goroutine-safe,多个 goroutine 可以同时访问一个 channel 而不会出现竞争问题
- 可以用于在 goroutine 之间存储和传递值
- 其语义是先入先出(FIFO)
- 可以导致 goroutine 的 block 和 unblock
- 获取锁
enqueue(task0)(这里是内存复制 task0)- 释放锁
- 获取锁
t = dequeue()(同样,这里也是内存复制)- 释放锁
ch <- task1ch <- task2ch <- task3M: OS 线程G: goroutineP: 调度上下文P拥有一个运行队列,里面是所有可以运行的 goroutine 及其上下文
G1会调用运行时的gopark,- 然后 Go 的运行时调度器就会接管
- 将
G1的状态设置为waiting - 断开
G1和M之间的关系(switch out),因此G1脱离M,换句话说,M空闲了,可以安排别的任务了。 - 从
P的运行队列中,取得一个可运行的 goroutineG - 建立新的
G和M的关系(Switch in),因此G就准备好运行了。 - 当调度器返回的时候,新的
G就开始运行了,而G1则不会运行,也就是 block 了。 G1会给自己创建一个sudog的变量- 然后追加到
sendq的等候队列中,方便将来的 receiver 来使用这些信息恢复G1。 G2先执行dequeue()从缓冲队列中取得task1给tG2从sendq中弹出一个等候发送的sudog- 将弹出的
sudog中的elem的值enqueue()到buf中 - 将弹出的
sudog中的 goroutine,也就是G1,状态从waiting改为runnable- 然后,
G2需要通知调度器G1已经可以进行调度了,因此调用goready(G1)。 - 调度器将
G1的状态改为runnable - 调度器将
G1压入P的运行队列,因此在将来的某个时刻调度的时候,G1就会开始恢复运行。 - 返回到 G2
- 然后,
G2给自己创建一个sudog结构变量。其中g是自己,也就是G2,而elem则指向t- 将这个
sudog变量压入recvq等候接收队列 G2需要告诉 goroutine,自己需要 pause 了,于是调用gopark(G2)- 和之前一样,调度器将其
G2的状态改为waiting - 断开
G2和M的关系 - 从
P的运行队列中取出一个 goroutine - 建立新的 goroutine 和
M的关系 - 返回,开始继续运行新的
goroutine
- 和之前一样,调度器将其
goroutine-safe
hchan中的lock mutex
存储、传递值,FIFO
- 通过
hchan中的环形缓冲区来实现
- 通过
导致 goroutine 的阻塞和恢复
hchan中的sendq和recvq,也就是sudog结构的链表队列- 调用运行时调度器 (
gopark(),goready()) - 接收方阻塞 → 发送方直接写入接收方的栈
- 发送方阻塞 → 接受法直接从发送方的
sudog中读取 - 先把所有需要操作的 channel 上锁
- 给自己创建一个
sudog,然后添加到所有 channel 的sendq或recvq(取决于是发送还是接收) - 把所有的 channel 解锁,然后 pause 当前调用
select的 goroutine(gopark()) - 然后当有任意一个 channel 可用时,
select的这个 goroutine 就会被调度执行。 - resuming mirrors the pause sequence
- 调用 Go 运行时调度器,这样可以保持 OS 线程不被阻塞
- 可以让 goroutine 醒来后不必获取锁
- 可以避免一些内存复制
其它 channel 的操作无缓冲 channel无缓冲的 channel 行为就和前面说的直接发送的例子一样:
selecthttps://golang.org/src/runtime/select.go
为什么 Go 会这样设计?Simplicity更倾向于带锁的队列,而不是无锁的实现。
“性能提升不是凭空而来的,是随着复杂度增加而增加的。” - dvyokov
后者虽然性能可能会更好,但是这个优势,并不一定能够战胜随之而来的实现代码的复杂度所带来的劣势。
Performance跨 goroutine 的栈读、写。
当然,任何优势都会有其代价。这里的代价是实现的复杂度,所以这里有更复杂的内存管理机制、垃圾回收以及栈收缩机制。
在这里性能的提高优势,要比复杂度的提高带来的劣势要大。
所以在 channel 实现的各种代码中,我们都可以见到这种 simplicity vs performance 的权衡后的结果。
|
channels 的特性
解析
构造 channel
回顾前面提到的 channel 的特性,特别是前两个。如果忽略内置的 channel,让你设计一个具有 goroutines-safe 并且可以用来存储、传递值的东西,你会怎么做?很多人可能觉得或许可以用一个带锁的队列来做。没错,事实上,channel 内部就是一个带锁的队列。 https://golang.org/src/runtime/chan.go
对于每一个 因为 发送、接收
为了方便描述,我们用
|
理解channel 工作原理以及源码的更多相关文章
- springmvc工作原理以及源码分析(基于spring3.1.0)
springmvc是一个基于spring的web框架.本篇文章对它的工作原理以及源码进行深入分析. 一.springmvc请求处理流程 二.springmvc的工作机制 三.springmvc核心源码 ...
- Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析
1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...
- 11.深入k8s:kubelet工作原理及源码分析
转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 源码版本是1.19 kubelet信息量是很大的,通过我这一篇文章肯定是讲不全的,大家可 ...
- Spring MVC工作原理及源码解析(四) ViewResolver实现原理及源码解析
0.ViewResolver原理介绍 根据视图的名称将其解析为 View 类型的视图,如通过 ModelAndView 中的视图名称将其解析成 View,View 是用来渲染页面的,也就是将 Mode ...
- Spring MVC工作原理及源码解析(二)DispatcherServlet实现原理及源码解析
1.DispatcherServlet 处理流程 从上一篇文章中Spring MVC原理图中我们可以看出:DispatcherServlet 在 Spring MVC框架 中处于核心位置,它负责协调和 ...
- Java并发包中Semaphore的工作原理、源码分析及使用示例
1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...
- 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]
目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...
- 【MVC - 参数原理】详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]
前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/spring ...
- Spring MVC工作原理及源码解析(一) MVC原理介绍、与IOC容器整合原理
MVC原理介绍 Spring MVC原理图 上图是Spring MVC工作原理图(图片来自网上搜索),根据上图,我们可以得知Spring MVC的工作流程如下: 1.用户(客户端,即浏览器)发送请求至 ...
随机推荐
- obj-c编程11:内存管理和ARC(自动引用计数)
乖乖隆地洞,这篇文章内容可是不得了,内存管理哦!首先,这个要是搞不明白,你就等着进程莫名其妙的挂死,或是疯狂申请内存却不释放,结果被OS杀死,不管是"自杀"还是"他杀&q ...
- python 3下基于select模型的事件驱动机制程序
它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程.它的流程如图: 当用户进程调用了select,那么整个 ...
- miniUI input设置默认值,js获取年月注意事项,数据库nvl函数使用
2017-6-5周一,今天碰到的一个需求是:两税附征模块进入页面筛选时间默认值为当前月的上一个月,并根据筛选结果显示数据,我们用的框架为miniUI. 坑1: 默认值设置,刚刚接触miniUI,对里面 ...
- 【CloverETL培训】题目
具体要求: 导入: 1.在CRM中,创建相应物理表,存储Follow/Binding记录.openid作为逻辑主键 2.Follow/Binding导入相互不影响,一个失败另外一个继续执行 3.Fol ...
- win10 下安装mysql服务器社区版本mysql-5.7.22-winx64
下载 下载: http://dev.mysql.com/downloads/mysql/ 解压到C盘 添加环境变量path 添加环境变量 右击我的电脑->属性->高级系统设置->高级 ...
- Google Bigtable (中文版)
http://dblab.xmu.edu.cn/post/google-bigtable/ Abstract BigTable是一个分布式存储系统,它可以支持扩展到很大尺寸的数据:PB级别的数据,包含 ...
- Hadoop的Python框架指南
http://www.oschina.NET/translate/a-guide-to-Python-frameworks-for-Hadoop 最近,我加入了Cloudera,在这之前,我在计算生物 ...
- Java永久代去哪儿了
http://www.infoq.com/cn/articles/Java-PERMGEN-Removed 在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法 ...
- PHP采用Cookie实现 购物车
先来看一下逻辑分析图:
- C#备份及还原数据库的实现
使用前要导入SQLDMO.dll 下载地址:http://down.51cto.com/data/853937 1.在用户的配置时,我们需要列出当前局域网内所有的数据库服务器,并且要列出指定服务器的所 ...