Golang并发编程有缓冲通道和无缓冲通道(channel)
无缓冲通道
是指在接收前没有能力保存任何值得通道。
这种类型的通道要求发送goroutine和接收goroutine同时准备好,才能完成发送和接收操作。如果两个goroutine没有同时准备好,通道会导致先执行发送或接收操作的goroutine阻塞等待。
这种对通道进行发送和接收的交互行为本身就是同步的,其中任意一个操作都无法离开另一个操作单独存在。

上图所示,如同接力赛。根据图编号观察①两个协程,创建好了通道②一个往通道里放,这时候两边阻塞④这时候另一个协程要接⑤另一个协程取出来,从①-⑤都是阻塞的,⑥才完成交接,才不会阻塞。
再比喻: 就是一个送信人去你家门口送信 ,你不在家 他不走,你一定要接下信,他才会走。
无缓冲channel创建
ch := make(chan int, ) //第二个参数为0,或者不写第二个参数
如果没有指定缓冲区容量,那么该通道就是同步的,因此会阻塞到发送者准备好发送和接收者准备好接收。
代码案例
package main import (
"fmt"
"time"
) func main() {
//创建一个无缓存的channel
ch := make(chan int, ) //len(ch)缓冲区剩余数据个数, cap(ch)缓冲区大小,两者这里永远都是0
fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch)) //新建协程
go func() {
for i := ; i < ; i++ { //写三次
fmt.Printf("子协程:i = %d\n", i)
ch <- i //往chan写内容
fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))
}
}() //延时2秒
time.Sleep( * time.Second) for i := ; i < ; i++ { //必须读三次
num := <-ch //读管道中内容,没有内容前,阻塞
fmt.Println("num = ", num)
} }
len(ch) = , cap(ch)=
子协程:i =
num =
len(ch) = , cap(ch)=
子协程:i =
len(ch) = , cap(ch)=
子协程:i =
num =
num =
流程分析
主协程执行到这里,阻塞两秒
//延时2秒
time.Sleep( * time.Second) //两秒钟时间子协程肯定把for循环执行完毕,但这里也会出现阻塞
//阻塞原因是:当执行到往通道写数据是无缓冲的,对方不读之前会阻塞。也就是,在主协程等着子协程写完,但是主协程还没到读的时候,这时候出现阻塞,等到主协程读完数据才会往下走。
可以执行观察一下程序的执行卡顿观察阻塞
for i := ; i < ; i++ { //写三次
fmt.Printf("子协程:i = %d\n", i)
ch <- i //往chan写内容
fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))
}
打印结果分析:首先子协程for循环往管道里写入一个数据,紧接着主协程for循环出现阻塞,然后主协程for循环从管道读数据,读完了打印。主协程打印完,子协程for循环继续给管道数据,但也有可能主协程读完数据没来得及打印,子协程就把数据写入管道并打印完毕,因为两个是同时并行的。
有缓冲通道
指通道可以保存多个值。
如果给定了一个缓冲区容量,那么通道就是异步的,只要缓冲区有未使用空间用于发送数据,或还包含可以接收的数据,那么其通信就会无阻塞地进行

上图所示:
①右侧的goroutine正在从通道接收一个值。
②右侧的goroutine独立完成了接手值得动作,而左侧的goroutine正在发送一个新值到通道里。
③左侧的goroutine还在向通道发送新值,而右侧的goroutine正在从通道接收另一个值。这个步骤里的两个操作既不是同步,也不会互相阻塞。
④所有的发送和接收都完成,而通道里还有几个值,也有一些空间可以存储更多的值
有缓冲channel创建
ch := make(chan int, ) //容量是3
代码案例
package main import (
"fmt"
"time"
) func main() {
//创建一个有缓存的channel
ch := make(chan int, ) //容量是3 //len(ch)缓冲区剩余数据个数, cap(ch)缓冲区大小
fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch)) //新建协程
go func() {
for i := ; i < ; i++ { //这里数据量大于管道容量,会出阻塞
ch <- i //往chan写内容,如果主协程没读的话,写满3个就会阻塞在此
fmt.Printf("子协程[%d]: len(ch) = %d, cap(ch)= %d\n", i, len(ch), cap(ch))
}
}() //延时
time.Sleep( * time.Second) for i := ; i < ; i++ { //这里数据量大于管道容量,会出阻塞
num := <-ch //读管道中内容,没有内容前,阻塞
fmt.Println("num = ", num)
} }
len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
num =
num =
num =
num =
子协程[]: len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
num =
num =
num =
num =
num =
子协程[]: len(ch) = , cap(ch)=
子协程[]: len(ch) = , cap(ch)=
num =
总结一下有缓冲channel和无缓冲channel的特点与不同
无缓冲的与有缓冲channel有着重大差别,那就是一个是同步的 一个是非同步的。
比如
c1:=make(chan int) 无缓冲
c2:=make(chan int,) 有缓冲
c1<-
无缓冲: 不仅仅是向 c1 通道放 1,而是一直要等有别的携程 <-c1 接手了这个参数,那么c1<-1才会继续下去,要不然就一直阻塞着。
有缓冲: c2<-1 则不会阻塞,因为缓冲大小是1(其实是缓冲大小为0),只有当放第二个值的时候,第一个还没被人拿走,这时候才会阻塞。
Golang并发编程有缓冲通道和无缓冲通道(channel)的更多相关文章
- Golang - 并发编程
目录 Golang - 并发编程 1. 并行和并发 2. go语言并发优势 3. goroutine是什么 4. 创建goroutine 5. runtime包 6. channel是什么 7. ch ...
- Golang并发编程——goroutine、channel、sync
并发与并行 并发和并行是有区别的,并发不等于并行. 并发 两个或多个事件在同一时间不同时间间隔发生.对应在Go中,就是指多个 goroutine 在单个CPU上的交替运行. 并行 两个或者多个事件在同 ...
- golang并发编程
golang并发编程 引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止go ...
- golang并发编程goroutine+channel(一)
go语言的设计初衷除了在不影响程序性能的情况下减少复杂度,另一个目的是在当今互联网大量运算下,如何让程序的并发性能和代码可读性达到极致.go语言的并发关键词 "go" go dos ...
- Golang并发编程优势与核心goroutine及注意细节
Go语言为并发编程而内置的上层API基于CSP(communication sequential processes,顺序通信进程)模型.这就意味着显式锁都是可以避免的,比如资源竞争,比如多个进程同时 ...
- Golang并发编程基础
硬件 内存 作为并发编程一个基础硬件知识储备,首先要说的就是内存了,总的来说在绝大多数情况下把内存的并发增删改查模型搞清楚了其他的基本上也是异曲同工之妙. 内存芯片--即我们所知道的内存颗粒,是一堆M ...
- Go语言的通道(1)-无缓冲通道
前言: 上文中我们采用了[原子函数]已经[共享锁]两种方式分别对多个goroutine进行了同步,但是在go语言中提供了另一种更好的方式,那就是使用通道(Channel). 一.通道是什么? 其实无论 ...
- golang并发编程的两种限速方法
引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止goroutine将资源耗 ...
- Golang并发编程进程通信channel了解及简单使用
概念及作用 channel是一个数据类型,用于实现同步,用于两个协程之间交换数据.goroutine奉行通过通信来共享内存,而不是共享内存来通信.引用类型channel是CSP模式的具体实现,用于多个 ...
随机推荐
- (转)Springboot日志配置(超详细,推荐)
Spring Boot-日志配置(超详细) 更新日志: 20170810 更新通过 application.yml传递参数到 logback 中. Spring Boot-日志配置超详细 默认日志 L ...
- Java 基础 常用API ( 正则表达式,Date类,DateFormat类,Calendar类 )
正则表达式 正则表达式的概念 正则表达式(英语:Regular Expression,在代码中常简写为regex). 正则表达式是一个字符串,使用单个字符串来描述.用来定义匹配规则,匹配一系列符合某个 ...
- Java 基础 引用数据类型 和 流程控制
引用数据类型 与定义基本数据类型变量不同,引用数据类型的变量定义及复制有一个相对固定的步骤和格式: 数据类型 变量名 = new 数据类型(); 如:String st = new String(); ...
- zabbix 监控openshift pod状态
需求: pod中的容器重启一次则报警通知 pod非Runing 状态则报警 pod中的容器非true状态则报警 三个需求其实是有点重叠的 pod重启期间pod肯定会有非Running状态,只要有重启报 ...
- Python才排第8名!2018增速最快TOP 10编程语言盘点
在技术前沿的硅谷,开发者们不仅要学习多种热门的编程语言,还要时时盯着新的编程语言的崛起,生怕自己掉队. 作为世界最大开源软件社区,Github每年都会发布年度Octoverse报告,向大家展示年度最流 ...
- Element-ui的表单中怎么添加正则校验
1. 以中国大陆手机号验证为例 // 这是组价的代码 <el-form-item prop="mobile"> <el-input type="text ...
- git stash 用法总结和注意点
常用git stash命令: (1)git stash save "save message" : 执行存储时,添加备注,方便查找,只有git stash 也要可以的,但查找时不 ...
- eclipse 把鼠标指针放在错误的语句上 提示快速修正 不见了的解决方法
Window->Preferences->Java->Editor->Hovers 将[Combined Hover]选择即可,如果第一个[Variable Values]已经 ...
- SpringMVC注解式开发之接收请求参数
逐个接收(涉及注解@RequestParam) index.jsp的name必须和后端的名字一致,第一种才可以实现. 以对象形式整合接收 域属性参数的接收 数组或集合参数的接收 restfull风格传 ...
- Ajax技术之XMLHttpRequest(二)【XMLHttpRequest常用方法和属性】
一.XMLHttpRequest中常用的方法: (1)open()方法:用于设置进行异步请求目标的URL.请求方法以及其他参数信息. 函数原型:open("method",&quo ...