无缓冲通道

是指在接收前没有能力保存任何值得通道。
这种类型的通道要求发送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. Python实现文字聊天室

    你是否想过用所学的Python开发一个图形界面的聊天室程序啊? 像这样的: 如果你想开发这样一个有点怀旧风格的聊天程序,那么可以接着看: 要开发这个聊天程序,你需要具备以下知识点: asyncore ...

  2. js图的数据结构处理----普里姆算法

    //求加权无向连通图的MST的贪心算法 //最小树,最小路径联通各个点 function PRIM(){ var graph = [ [], [undefined,Infinity, 23 ,Infi ...

  3. Dart- move html element

    今天给出一个例程,像是个小游戏!哈哈 一 html //anagram.html <!DOCTYPE HTML> <html> <head> <title&g ...

  4. smali参数引用说明

    比如非静态函数test(IJZ)V; p0表示this p1 I p2 J 以此类推

  5. JavaScript学习笔记之call和apply

    前端的知识面太广了,想要记住所有知识点是不可能的,所以将这些学过的记录下来,随时都可以翻开来参考 1.call方法 调用一个对象的一个方法,call(this, arg1, arg2,argN);用来 ...

  6. DoTween

    dotween最原始的用法 using System.Collections; using System.Collections.Generic; using UnityEngine; using D ...

  7. 读写App.config配置文件的方法

    我们经常会希望在程序中写入一些配置信息,例如版本号,以及数据库的连接字符串等.你可能知道在WinForm应用程序中可以利用Properties.Settings来进行类似的工作,但这些其实都利用了Ap ...

  8. javascript 面向对象之路.1 - 小蜜蜂

    写这个系列文章是想通过几个案例来学习javascript html5 css3,其实这个小游戏谁都能做出来,但对于一个作为后端.net程序员的我来说还是有学习的必要,毕竟javascript的面向对象 ...

  9. VS2017

    Visual Studio常用快捷键https://www.cnblogs.com/DonetRen/p/8182911.htmlVisual Studio 2017 Product Family S ...

  10. python3 TypeError: a bytes-like object is required, not 'str'

    在学习<Python web开发学习实录>时, 例11-1: # !/usr/bin/env python # coding=utf-8 import socket sock = sock ...