无缓冲阻塞 chan 杂谈

2024-06-12 15:38
文章标签 阻塞 缓冲 杂谈 chan

本文主要是介绍无缓冲阻塞 chan 杂谈,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

chan类似队列版管道,无缓冲chan看起来好像是全局变量,通过它可让多个goroutine间通信。 这其实隐含一个事实,chan阻塞会引发goroutine上下文切换,而切换到哪一个可执行goroutine由go调度器决定(与阻塞chan相关)。go当前能够使用的goroutine,必须在其待命队列中,否则会产生死锁。

上下文切换

多进程多线程都具备上下文切换,即保存恢复现场的能力。goroutine的上下文切换实现,是在用户态基础上进行,只不过它涉及到的资源比线程更少,如产生一个线程系统调用分配内存通常在1M,而goroutine只有2kb,此外在使用寄存器,段位上,goroutine也只需3个左右,而线程则通常在10个左右。

无缓冲阻塞

go调度器对goroutine的使用配合chan,具有有序性(在高并发访问对象时,可用chan这种特性让访问请求隐性排队,解决竞态问题)。main函数是特殊的入口goroutine,若有阻塞代码,运行时runtime会寻找已入队列的goroutine并在适当的时机调用它。chan并不是全局变量,确切来说它的读/写阻塞会触发当前goroutine执行权转移,它只是个通信器。好似打电话,必须先知道对方号码并有连线,才能正常工作,若顺序不对,表现在golang中便是死锁

Blocking

package mainimport ("fmt"
)func f1(in chan int) {fmt.Println(<-in)
}func main() {out := make(chan int)out <- 2go f1(out)
}

上述代码会产生死锁,main入口goroutine,通道out产生了发送阻塞,此时runtime会尝试调度与out通道读相关的goroutine执行,但可惜的是,在 out <- 2之前,并没有向go执行器队列加入与out读相关的goroutine。换句话而言,f1压根就没入队,没有执行机会。

unblocking

 package mainimport "fmt"func main() {out := make(chan int)go f1(out)// 此处顺序大有讲究,在使用发送通道之前必需想好数据接收的退路,f1即是out <- 2}func f1(in chan int) {fmt.Println(<-in)}

chan vs 全局变量

上文提到chan类似管道,管道顾名思义一端进一端出,很形象表明了一个连接器。go中的chan连接goroutine,游离于众多goroutine之间,功用性与全局变量有得一拼。但chan绝对不是全局变量,一个全局变量,可以在同一函数体内重复读写,但对无缓冲chan而言是不可以,原因在同一goroutine内对同一chan读写时,存在读或写阻塞面临切换上下文,另一个对应的永远没执行机会,如下

  • 无缓冲通道死锁
 package mainimport "fmt"func main() {ch := make(chan int)ch <- 5fmt.Println(<-ch)}
  • 有缓冲通道正常
 package mainimport "fmt"func main() {ch := make(chan int, 1)ch <- 5fmt.Println(<-ch)}

有缓冲通道,意味着在未超过当前通道限制数之前,当前的goroutine是非阻塞,不会发生上下文切换,即当前goroutine的控制权不发生转移,runtime也就不会去寻求其它相关goroutine执行。

小结

  • 无缓冲chan 进和出都会阻塞.
  • 有缓冲chan 先进先出队列, 出会一直阻塞到有数据, 进时当队列未满不会阻塞, 队列已满则阻塞.

这篇关于无缓冲阻塞 chan 杂谈的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1054629

相关文章

认知杂谈52

今天分享 有人说的一段争议性的话 I I 1拓展人脉很重要** 咱们活在这世上啊,得明白一件事儿,知识、逻辑能力和实战经验虽然重要,但确实都不是最关键的。真正关键的是要懂得怎么和那些手里有资源的人打交道。人脉那可真是一笔无形的大财富呢。你想想看,有时候一个有影响力的人帮你一把,那效果可比你累死累活干一年都强得多。 I I 就比如说,你要是认识个行业里的大牛,他可能给你介绍个特别好的工

springboot体会BIO(阻塞式IO)

使用springboot体会阻塞式IO 大致的思路为: 创建一个socket服务端,监听socket通道,并打印出socket通道中的内容。 创建两个socket客户端,向socket服务端写入消息。 1.创建服务端 public class RedisServer {public static void main(String[] args) throws IOException {

多路转接之select(fd_set介绍,参数详细介绍),实现非阻塞式网络通信

目录 多路转接之select 引入 介绍 fd_set 函数原型 nfds readfds / writefds / exceptfds readfds  总结  fd_set操作接口  timeout timevalue 结构体 传入值 返回值 代码 注意点 -- 调用函数 select的参数填充  获取新连接 注意点 -- 通信时的调用函数 添加新fd到

多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

目录 一、LinkedBlockingDeque是什么 二、核心属性详解 三、核心方法详解 addFirst(E e) offerFirst(E e) putFirst(E e) removeFirst() pollFirst() takeFirst() 其他 四、总结 一、LinkedBlockingDeque是什么 首先queue是一种数据结构,一个集合中

多线程篇(阻塞队列- LinkedBlockingQueue)(持续更新迭代)

目录 一、基本概要 1. 构造函数 2. 内部成员 二、非阻塞式添加元素:add、offer方法原理 offer的实现 enqueue入队操作 signalNotEmpty唤醒 删除线程(如消费者线程) 为什么要判断if (c == 0)时才去唤醒消费线程呢? 三、阻塞式添加元素:put 方法原理 图解:put线程的阻塞过程 四、非阻塞式移除:poll方法原理 dequ

认知杂谈54

I I 内容摘要: 这篇内容主要有以下几个要点:首先,沟通不在一个调时可学习人际交往心理学知识、线上课程及关注名师来改善。其次,挑房子、工作、搭档和人生伴侣要谨慎,找心灵相通能共同进步的人。再者,远离负能量的人,多跟积极向上的人相处攒正能量。然后,人生如爬山,要专注自身步伐,不与他人比较,坚持目标,可通过看《微习惯》、用专注 APP、参加训练营提升专注力和自律能力。此外,别瞎操心他人,每个人有自

数字电路专题:verilog 阻塞赋值和非阻塞赋值

verilog 阻塞赋值 和 非阻塞赋值 “=”阻塞赋值, ”<=”非阻塞赋值。阻塞赋值为执行完一条赋值语句,再执行下一条,可理解为顺序执行,而且赋值是立即执行; 非阻塞赋值可理解为并行执行,不考虑顺序,在 always 块语句执行完成后,才进行赋值。 如下面的阻塞赋值: //代码如下:module top(din,a,b,c,clk);input din;input clk;out

多线程篇(阻塞队列- ArrayBlockingQueue)(持续更新迭代)

目录 一、源码分析 1. 先看个关系图 2. 构造方法 3. 核心属性 4. 核心功能 入队(放入数据) 出队(取出数据) 5. 总结 一、源码分析 1. 先看个关系图 PS:先看个关系图 ArrayBlockingQueue是最典型的有界阻塞队列,其内部是用数组存储元素的, 初始化时需要指定容量大小利用 ReentrantLock 实现线程安全。 在生产者

io本质+io效率本质,5种io模型(介绍,异步/同步区别,阻塞/非阻塞区别)

目录 5种io模型 io引入 io的本质 io效率的本质 模型引入 以钓鱼为例 效率最高的方式 异步io和同步io的区别 阻塞式和非阻塞式io的区别 介绍 阻塞式io ​编辑 非阻塞式io ​编辑 信号驱动式io ​编辑 多路转接/复用 ​编辑 异步io 5种io模型 io引入 io的本质 以read ,write为例: 如果底层缓冲区没有数据

工作集、granule、缓冲区、缓冲池概念及关系?

工作集、granule、缓冲区、缓冲池概念及关系? granule:为了让内存在db_chache_size和shared_pool_size之间高效的移动,oracle在9i重构SGA,使用固定大小的内存块即为granule。这个参数就是为什么当你分配给shared pool值的时候,为什么有时候比你分配的值要大一点,但是granule的整数倍。 缓冲区:内存存放数据的地方,类似于数