无缓冲通道

是指在接收前没有能力保存任何值得通道。
这种类型的通道要求发送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)的更多相关文章

  1. Golang - 并发编程

    目录 Golang - 并发编程 1. 并行和并发 2. go语言并发优势 3. goroutine是什么 4. 创建goroutine 5. runtime包 6. channel是什么 7. ch ...

  2. Golang并发编程——goroutine、channel、sync

    并发与并行 并发和并行是有区别的,并发不等于并行. 并发 两个或多个事件在同一时间不同时间间隔发生.对应在Go中,就是指多个 goroutine 在单个CPU上的交替运行. 并行 两个或者多个事件在同 ...

  3. golang并发编程

    golang并发编程 引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止go ...

  4. golang并发编程goroutine+channel(一)

    go语言的设计初衷除了在不影响程序性能的情况下减少复杂度,另一个目的是在当今互联网大量运算下,如何让程序的并发性能和代码可读性达到极致.go语言的并发关键词 "go" go dos ...

  5. Golang并发编程优势与核心goroutine及注意细节

    Go语言为并发编程而内置的上层API基于CSP(communication sequential processes,顺序通信进程)模型.这就意味着显式锁都是可以避免的,比如资源竞争,比如多个进程同时 ...

  6. Golang并发编程基础

    硬件 内存 作为并发编程一个基础硬件知识储备,首先要说的就是内存了,总的来说在绝大多数情况下把内存的并发增删改查模型搞清楚了其他的基本上也是异曲同工之妙. 内存芯片--即我们所知道的内存颗粒,是一堆M ...

  7. Go语言的通道(1)-无缓冲通道

    前言: 上文中我们采用了[原子函数]已经[共享锁]两种方式分别对多个goroutine进行了同步,但是在go语言中提供了另一种更好的方式,那就是使用通道(Channel). 一.通道是什么? 其实无论 ...

  8. golang并发编程的两种限速方法

    引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止goroutine将资源耗 ...

  9. Golang并发编程进程通信channel了解及简单使用

    概念及作用 channel是一个数据类型,用于实现同步,用于两个协程之间交换数据.goroutine奉行通过通信来共享内存,而不是共享内存来通信.引用类型channel是CSP模式的具体实现,用于多个 ...

随机推荐

  1. iText实现导出pdf文件java代码实现例子

    ///////////////////////////////////主类////////////////////////////////////////// package com.iText; i ...

  2. CentOS6.5安装Elasticsearch1.7.5

    1. 首页到官方网站下载最新安装包 https://www.elastic.co/downloads/elasticsearch  elasticsearch-1.7.5.tar.gz 2. 将软件包 ...

  3. vim 常用

    Format JSON :%!python -m json.tool 1. define custom function and use it define function in .vimrc fu ...

  4. Express web框架 upload file

    哈哈,敢开源,还是要有两把刷子的啊 今天,看看node.js 的web框架 Express的实际应用 //demo1 upload file <html><head><t ...

  5. Unity3d打包发布Android程序

    unty3d这个款游戏引擎的强大之处就是编写一个程序.可以多平台发布.我的是安卓手机.所以此文介绍下发布安卓的过程 发布安卓前. 1:需要配置java环境.这里之前写过一篇java的配置  http: ...

  6. GIS 网站 参考网站

    GIS 网站 参考:https://malagis.com/arcgis-operate-videos-example-38-summary.html

  7. sift拟合详解

    1999年由David Lowe首先发表于计算机视觉国际会议(International Conference on Computer Vision,ICCV),2004年再次经David Lowe整 ...

  8. ProxySQL(读写分离)部署

    proxySQL是MySQL的中间件产品,是灵活强大的代理层,实现读写分离,支持Query路由功能,支持动态指定某个SQL进行缓存,支持动态加载配置,故障切换和一些SQL 过滤功能 环境: 192.1 ...

  9. 第一章 HTML基本标签

    1.HTML:HTML:超文本标签语言(标签又称标记.元素).浏览器:“解释和执行”HTML源码的工具 (运行网页的工具APP).客户端:享受服务的计算机服务器:提供服务的计算机 2.基本框架(网页最 ...

  10. mac install wget

    没有Wget的日子是非常难过的,强大的Mac OS 下安装Wget非常简单 下载一个Wget的源码包,http://www.gnu.org/software/wget/ ftp下载地址:ftp://f ...