Golang通道的无阻塞读写的方法示例
无论是无缓冲通道,还是有缓冲通道,都存在阻塞的情况,但其实有些情况,我们并不想读数据或者写数据阻塞在那里,有1个唯一的解决办法,那就是使用select结构。
这篇文章会介绍,哪些情况会存在阻塞,以及如何使用select解决阻塞。
阻塞场景
阻塞场景共4个,有缓存和无缓冲各2个。
无缓冲通道的特点是,发送的数据需要被读取后,发送才会完成,它阻塞场景:
- 通道中无数据,但执行读通道。
- 通道中无数据,向通道写数据,但无协程读取。
// 场景1
func ReadNoDataFromNoBufCh() {
noBufCh := make(chan int)
<-noBufCh
fmt.Println("read from no buffer channel success")
// Output:
// fatal error: all goroutines are asleep - deadlock!
}
// 场景2
func WriteNoBufCh() {
ch := make(chan int)
ch <- 1
fmt.Println("write success no block")
// Output:
// fatal error: all goroutines are asleep - deadlock!
}
注:示例代码中的Output注释代表函数的执行结果,每一个函数都由于阻塞在通道操作而无法继续向下执行,最后报了死锁错误。
有缓存通道的特点是,有缓存时可以向通道中写入数据后直接返回,缓存中有数据时可以从通道中读到数据直接返回,这时有缓存通道是不会阻塞的,它阻塞的场景是:
- 通道的缓存无数据,但执行读通道。
- 通道的缓存已经占满,向通道写数据,但无协程读。
// 场景1
func ReadNoDataFromBufCh() {
bufCh := make(chan int, 1)
<-bufCh
fmt.Println("read from no buffer channel success")
// Output:
// fatal error: all goroutines are asleep - deadlock!
}
// 场景2
func WriteBufChButFull() {
ch := make(chan int, 1)
// make ch full
ch <- 100
ch <- 1
fmt.Println("write success no block")
// Output:
// fatal error: all goroutines are asleep - deadlock!
}
使用Select实现无阻塞读写
select是执行选择操作的一个结构,它里面有一组case语句,它会执行其中无阻塞的那一个,如果都阻塞了,那就等待其中一个不阻塞,进而继续执行,它有一个default语句,该语句是永远不会阻塞的,我们可以借助它实现无阻塞的操作。
下面示例代码是使用select修改后的无缓冲通道和有缓冲通道的读写,以下函数可以直接通过main函数调用,其中的Ouput的注释是运行结果,从结果能看出,在通道不可读或者不可写的时候,不再阻塞等待,而是直接返回。
// 无缓冲通道读
func ReadNoDataFromNoBufChWithSelect() {
bufCh := make(chan int)
if v, err := ReadWithSelect(bufCh); err != nil {
fmt.Println(err)
} else {
fmt.Printf("read: %d\n", v)
}
// Output:
// channel has no data
}
// 有缓冲通道读
func ReadNoDataFromBufChWithSelect() {
bufCh := make(chan int, 1)
if v, err := ReadWithSelect(bufCh); err != nil {
fmt.Println(err)
} else {
fmt.Printf("read: %d\n", v)
}
// Output:
// channel has no data
}
// select结构实现通道读
func ReadWithSelect(ch chan int) (x int, err error) {
select {
case x = <-ch:
return x, nil
default:
return 0, errors.New("channel has no data")
}
}
// 无缓冲通道写
func WriteNoBufChWithSelect() {
ch := make(chan int)
if err := WriteChWithSelect(ch); err != nil {
fmt.Println(err)
} else {
fmt.Println("write success")
}
// Output:
// channel blocked, can not write
}
// 有缓冲通道写
func WriteBufChButFullWithSelect() {
ch := make(chan int, 1)
// make ch full
ch <- 100
if err := WriteChWithSelect(ch); err != nil {
fmt.Println(err)
} else {
fmt.Println("write success")
}
// Output:
// channel blocked, can not write
}
// select结构实现通道写
func WriteChWithSelect(ch chan int) error {
select {
case ch <- 1:
return nil
default:
return errors.New("channel blocked, can not write")
}
}
使用Select+超时改善无阻塞读写
使用default实现的无阻塞通道阻塞有一个缺陷:当通道不可读或写的时候,会即可返回。实际场景,更多的需求是,我们希望,尝试读一会数据,或者尝试写一会数据,如果实在没法读写,再返回,程序继续做其它的事情。
使用定时器替代default可以解决这个问题。比如,我给通道读写数据的容忍时间是500ms,如果依然无法读写,就即刻返回,修改一下会是这样:
func ReadWithSelect(ch chan int) (x int, err error) {
timeout := time.NewTimer(time.Microsecond * 500)
select {
case x = <-ch:
return x, nil
case <-timeout.C:
return 0, errors.New("read time out")
}
}
func WriteChWithSelect(ch chan int) error {
timeout := time.NewTimer(time.Microsecond * 500)
select {
case ch <- 1:
return nil
case <-timeout.C:
return errors.New("write time out")
}
}
结果就会变成超时返回:
read time out
write time out
read time out
write time out
转载于:https://www.cnblogs.com/xxcn/p/9907400.html
Golang通道的无阻塞读写的方法示例相关推荐
- 用js的document.write输出的广告无阻塞加载的方法(转)
一.广告代码分析 很多第三方地广告系统都是使用document.write来加载广告,如下面地一个javascript地广告链接. 代码如下: <script type=text/javascr ...
- 利用DuplicateHandle()无驱动的另类读写内存方法,理论上可以过游戏保护读写
突发奇想出的原创思路,在理论上经过完善应该可以做到过游戏保护无驱动读写内存 首先看一下MSDN对这个函数的定义 BOOL DuplicateHandle(HANDLE hSourceProcessHa ...
- 用js的document write输出的广告无阻塞加载的方法
一.广告代码分析 很多第三方的广告系统都是使用document.write来加载广告,如下面的一个javascript的广告链接. 代码如下: <script type="text/j ...
- Golang中各种永远阻塞的方法
在Golang中各种永远阻塞的姿势 Go的运行时的当前设计,假定程序员自己负责检测何时终止一个goroutine以及何时终止该程序. 可以通过调用os.Exit或从main()函数的返回来以正常方式终 ...
- 超越最新无监督域自适应方法,研究人员提轻量CNN新架构OSNet
作者 | Kaiyang Zhou, Xiatian Zhu, Yongxin Yang, Andrea Cavallaro, and Tao Xiang 译者 | TroyChang 编辑 | Ja ...
- WPF MVVM模式下的无阻塞刷新
MVVM模式下的无阻塞刷新的两种方法: //传统模式下的无刷新调用(主线程开新线程,新线程又调用主线程来更新UI) //第1步先在线程内部计算出需要绑定的数据 //第2步然后再使用Invoke/Beg ...
- 局域网服务器文件夹隐藏,局域网服务器共享文件夹访问权限设置win7隐藏无权限共享文件夹方法.docx...
局域网服务器共享文件夹访问权限设置win7隐藏无权限共享文件夹方法 ??局域网服务器共享文件夹访问权限设置.win7隐藏无权限共享文件夹的方法在局域网文件管理中,文件服务器共享文件的管理一直是当前网络 ...
- html5 js阻塞加载,js无阻塞加载和defer、async详解_白峰_前端开发者
无阻塞加载 把 下载是异步的没问题,但是每个javascript执行的时候还是同步的,就是先出现的script标签一定是先执行,即使是并行下载它是最后一个下载完成的,除非标有defer的script标 ...
- 无阻塞实时检测键盘输入
本人小白一枚,第一次写博客,个位大佬多多指教. 之前一直使用opencv,里面的waitkey函数对于实时检测键盘输入还是比较友好.但是最近只用c++开发之后发现不会怎么实现无阻塞读取键盘输入.查资料 ...
最新文章
- ADO.NET与ORM的比较(5):MyBatis实现CRUD
- oracle 2日dba 11g,Oracle 11gR2 注意revoke dba 会一并回收通过”quota“分配的表空间限额...
- 2020-09-17
- JavaScript事件的捕获阶段(Capture phase)
- php 置信区间 计算,深度学习篇-如何理解置信区间
- [原创]关于设置linux中vim 显示行号
- SAP License:药店ERP系统如何实施
- 9.6 awk(上);9.7 awk(下)
- 一台计算机重量,一台重量仅为1.85kg的游戏本 机械师F117毒药
- windows 10下解压.gz后缀文件
- 智慧安全:信息安全监控平台
- Python中index函数用法总结
- 【虫师--系列15】性能测试知多少---系统架构分析
- 新出炉彩色游戏——炸弹战争1.0版
- 今日头条 爬虫 java_Java爬虫实践:Jsoup+HttpUnit爬取今日头条、网易、搜狐、凤凰新闻...
- GitHub下载加速网站
- 关于com.lowagie.text包的报错问题
- python 换脸 github_如何用200行Python代码“换脸”
- 小米平板刷机shell怎么退_小米平板2如何一键解锁?刷机教程图解
- 在Vue中使用WebSocket+HighCharts+Canvas实现高性能的频谱瀑布图
热门文章
- 怎样格式化电脑_160G移动硬盘做PE启动盘 要怎样做
- python中全局变量和局部变量关键字_Python中全局变量和局部变量的理解与区别
- android popupwindow dialog区别,Android PopUpWindow使用详解
- mysql int 默认值 为ull_mysql的 约束 数据库设计 数据库 存储 触发器 mysql 权限问题...
- 生成html_HTML页面生成器:使用JavaScript和Node创建CLI
- windows下用elasticdump导入json数据到Elasticsearch中
- 不止面试题,笔记源码统统都有
- Android程序员面试必备的知识点,附答案
- 【408预推免复习】计算机组成原理之计算机的发展及应用
- 【django轻量级框架】在线视频教育系统设计与实现