理解channel 工作原理以及源码
- goroutines: 独立执行每个任务,并可能并行执行
- channels: 用于 goroutines 之间的通讯、同步
- goroutine-safe,多个 goroutine 可以同时访问一个 channel 而不会出现竞争问题
- 可以用于在 goroutine 之间存储和传递值
- 其语义是先入先出(FIFO)
- 可以导致 goroutine 的 block 和 unblock
- 获取锁
- enqueue(task0)(这里是内存复制 task0)
- 释放锁
- 获取锁
- t = dequeue()(同样,这里也是内存复制)
- 释放锁
- ch <- task1
- ch <- task2
- ch <- task3
- M: OS 线程
- G: goroutine
- P: 调度上下文- 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给- t
- G2从- 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 行为就和前面说的直接发送的例子一样: - select- https://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.用户(客户端,即浏览器)发送请求至 ... 
随机推荐
- Spring3.x企业应用开发实战-Spring+Hibernat架构分析
			1: 持久层设计 采用Spring注解方式省略了大量Hibernate ORM配置文件: BaseDAO减少DAO层代码量,只需要编写非通用型的持久层方法: 持久层提供分页支持: Hibernate ... 
- sublime使用技巧之集成VI
			熟悉开发工具,减少多余的操作流程有助于提高开发效率,而Sublime Text 2是sublime产品的经典版本,因此本文基于Sublime Text 2讲解sublime的使用技巧. VI的主要作用 ... 
- Django之AppConfig源码学习
			class AppConfig(object) 这个基类描述了一个Django应用以及它的配置信息. 属性: name:django应用的完整python路径,eg.'django.contrib.a ... 
- 关于Django Web应用架构设计开发的几个问题
			1.关于分层,做过传统JEE应用的同学肯定知道JEE应用会分很多个设计层.根据传统Web应用架构设计一般从上到下分这么几个层(太懒了,不画图了):Web前端层.Web后端交互层.业务层.基础数据设施层 ... 
- php进阶篇
			字符串调用: $name = 'eco'; echo $name; //eco //双引号会解析变量 echo "$name"; //eco //单引号不会解析变量 echo '$ ... 
- Centos下部署Flask
			尝试在Centos6.5下部署Flask应用并成功,记录一下步骤,参数为什么这样配置还需要再研究uwsgi和Nginx才能回答. Python版本升级2.7 测试机器centos6.5默认自带的pyt ... 
- 我们常说的 CAS 自旋锁是什么
			CAS(Compare and swap),即比较并交换,也是实现我们平时所说的自旋锁或乐观锁的核心操作. 它的实现很简单,就是用一个预期的值和内存值进行比较,如果两个值相等,就用预期的值替换内存值, ... 
- 服务治理利器Hystrix-理论篇
			引言 现在的大中型应用,很多都在朝着服务化.分布式的方向发展.这有多方面的考虑,比如说,方便治理.便于扩展.服务隔离等等.不过在带来如此多利好的同时,不可避免的也会带来麻烦,比如系统架构复杂.服务依赖 ... 
- Hadoop 3.x 新特性剖析系列2
			1.概述 接着上一篇博客的内容,继续介绍Hadoop3的其他新特性.其内容包含:优化Hadoop Shell脚本.重构Hadoop Client Jar包.支持等待Container.MapReduc ... 
- memset库函数
			头文件:#include <string.h> 定义函数:void * memset(void *s, int c, size_t n); 函数说明:memset()会将参数s 所 ... 
