无缓冲阻塞 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

相关文章

Java并发编程—阻塞队列源码分析

在前面几篇文章中,我们讨论了同步容器(Hashtable、Vector),也讨论了并发容器(ConcurrentHashMap、CopyOnWriteArrayList),这些工具都为我们编写多线程程序提供了很大的方便。今天我们来讨论另外一类容器:阻塞队列。   在前面我们接触的队列都是非阻塞队列,比如PriorityQueue、LinkedList(LinkedList是双向链表,它实现了D

【LinuxC语言】阻塞、回调与轮询快速理解

文章目录 前言阻塞阻塞的基本概念阻塞函数非阻塞函数区别 回调轮询 总结 前言 在Linux C语言编程中,阻塞、回调和轮询是三种常见的处理输入/输出(I/O)的方式。这些方法在处理网络通信、多线程编程和套接字编程等场景中都有广泛的应用。理解这三种方法的工作原理和使用场景,对于提高编程效率和程序性能至关重要。 阻塞 阻塞的基本概念 阻塞是一种同步操作,它会暂停程序的

「杂谈」Nanopore组装的拟南芥基因组效果如何?

使用的数据来自于一篇发在NC的拟南芥的基因组文章,文章用了minimap/miniasm 进行组装,然后用racon和Pilon进行polish, 最后拼接处62 contigs 且N50 = 12.3 Mb。 wget ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR217/003/ERR2173373/ERR2173373.fastq.gzseqkit seqk

第十六章 非阻塞I/O

第十六章、非阻塞式I/O 什么是阻塞socket和非阻塞socket?两者的具体区别是什么?     读操作         对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返回。当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数。当sockt的接收缓冲区中的数据大于期望读取的字节数时,读取期望读取的

浅解Node.js的异步非阻塞I/O模型

今天.NET老师在课堂上吹捧多线程编程,我就想为单线程抱个不平,因为Node的单线程异步非阻塞I/O模型,演绎了单线程编程的神话。 阻塞I/O程序执行过程中必然要进行很多I/O操作,读写文件、输入输出、请求响应等等。I/O操作时最费时的,至少相对于代码来说,在传统的编程模式中,举个例子,你要读一个文件,整个线程都暂停下来,等待文件读完后继续执行。换言之,I/O操作阻塞了代码的执行,极大地降低

【Linux】进程信号2——阻塞信号,捕捉信号

1.阻塞信号 1.1. 信号其他相关常见概念 在开始内容之前,先介绍一些信号的专业名词: 实际执行信号的处理动作称为信号递达(Delivery)信号从产生到递达之间的状态,称为信号未决(Pending)(就是收到信号,但没有执行信号对应的动作)进程可以选择阻塞(Block)某个信号,阻塞的信号就是收到信号,但是一直处于未决状态。忽略信号也是一种递达动作。未决就是未决,阻塞就是阻塞。没有收到信

read函数阻塞和非阻塞

read函数只是一个通用的读文件设备的接口。是否阻塞需要由设备的属性和设定所决定。一般来说,读字符终端、网络的socket描述字,管道文件等,这些文件的缺省read都是阻塞的方式。如果是读磁盘上的文件,一般不会是阻塞方式的。但使用锁和fcntl设置取消文件O_NOBLOCK状态,也会产生阻塞的read效果

同步和异步、阻塞和非阻塞概念(转)

同步和异步的概念 - rainbow70626 - 博客园 --------------------------------------------------------------------------------------------------------------------------------- 同步是指:当程序1调用程序2时,程序1停下不动,直到程序2完成回到程序1来,程

多线程(Lock锁,死锁,等待唤醒机制,阻塞队列,线程池)

Lock锁 虽然我们可以理解同步代码块和同步方法的锁对象问题但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作Lock中提供了获得锁和释放锁的方法 void lock():获得锁void unlock():释放锁 即手动上锁、手动释放锁 L

设置浏览器不缓冲

1)有一些网站要求及时性很高,所以就必须让浏览器不缓冲页面才可以达到要求:代码如下 1 //指定页面不缓冲2 response.setDataHeader("Expires",-1);3 //保证兼容性4 response.setHeader("Cache-Control","no-cache");5 response.setHeader("Pr