原文: https://www.jianshu.com/p/147bd63801b6

--------------------------------------

Go与其他语言不一样,它从语言层面就已经支持并发,不需要我们依托Thread库新建线程。Go中的channel机制使我们不用过多考虑锁和并发安全问题。channel提供了一种goroutine之间数据流传输的方式。

今天我想从一个常见的deadlock error开始,讨论一下channel的特性。

如果运行以下程序:

var ch = make(chan int)

func main() {
ch <- 1
<-ch // 没有这行代码也会报同样的错误
}

terminal会报如下错误:

fatal error: all goroutines are asleep - deadlock!

回顾channel(信道)的概念,大致上来说,信道是goroutine之间相互沟通的管道,信道中数据的流通代表着goroutine之间内存的共享。宏观上来讲,信道有点像其他语言中的队列(queue),遵循先进先出的规则。

信道分为无缓冲信道(即unbuffered channel)和有缓冲信道(buffered channel)。对于无缓冲的信道来说,我们默认信道的发消息(send)和收消息(receive)都是阻塞(block)的。换句话来说,无缓冲的信道在收消息和发消息的时候,goroutine都处于挂起状态。除非另一端准备好,否则goroutine无法继续往下执行。

上面的那段程序便是一个明显的错误样例。在main函数执行到ch <- 1的时候main(也是一个goroutine)便已挂起,而并没有其他goroutine负责接收消息,而下面一句 <-ch 永远无法执行,系统便自动判为timeout返回error。这种所有线程或者进程都在等待资源释放的情况,我们便把它称之为死锁。

死锁是一个非常有意思的话题,常见的死锁大致分为以下几类:
i. 只在单一goroutine里操作信道,例子如上。
ii. 串联信道中间一环挂起,举例如下:

var ch1 chan int = make(chan int)
var ch2 chan int = make(chan int) func say(s string) {
fmt.Println(s)
ch1 <- <- ch2 // ch1 等待 ch2流出的数据
} func main() {
go say("hello")
<- ch1 // 堵塞主线
}

ch1等待ch2留出数据,然而ch2并没有发出数据导致goroutine阻塞,解决方案是给ch2喂数据:

func feedCh2(ch chan int) {
ch <- 2
}

iii. 非缓冲信道不成对出现:

c, quit := make(chan int), make(chan int)

go func() {
c <- 1 // c通道的数据没有被其他goroutine读取走,堵塞当前goroutine
quit <- 0 // quit始终没有办法写入数据
}() <- quit // quit 等待数据的写

当然,并非所有不成对出现的非缓冲信道都会报错:

func say(ch chan int) {
ch <- 1
} func main() {
ch := make(chan int)
go say(ch)
}

有意思的是,虽然say函数挂起等待信道接收消息,但是main goroutine并没有被阻塞,在main函数返回后程序依然可以自动终止。

关于缓冲信道将会在之后的文章中介绍,如有意见还请指教。

Reference: http://blog.csdn.net/kjfcpua/article/details/18265441

作者:Solonk8
链接:https://www.jianshu.com/p/147bd63801b6
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

[转]从Deadlock报错理解Go channel机制的更多相关文章

  1. caffe运行报错:datum channel>0(0:0)

    caffe在运行的时候报错:datum channel>0(0:0) 错误原因:数据通道错误,caffe不能识别 解决方案:不告诉你

  2. netty-websocket-spring-boot-starter关闭报错 io/netty/channel/AbstractChannel$AbstractUnsafe io/netty/util/concurrent/GlobalEventExecutor

    报错 java.lang.NoClassDefFoundError: io/netty/channel/AbstractChannel$AbstractUnsafe$ at io.netty.chan ...

  3. jmeter-利用While Controller控制器实现接口报错时的重试机制

    预期功能:在jmter脚本报错的时候重试,最多重试5次 1.添加While Controller 2.添加请求 3.添加断言,在断言不符合预期的时候加上代码:vars.put("status ...

  4. “ping”简单报错理解

    了解ABC类IP地址:网络.主机.子网.广播. ———————————————————————————- 学会ping: ping www.itxdm.me 网络检测:ping某一主机可以正常启动!( ...

  5. RedisCluster的rename机制失败报错,解决又是数据倾斜问题

    需求说明:spring session中的用户session更新是更新key的名字,所以对于key的操作时需要用newkey 替换oldkey value值只允许存在一个,这里用到rename就很合适 ...

  6. 从返回值未报错得到的对于java finally理解

    不多说了,直接看图 这个代码来自<深入理解java虚拟机(第二版)>,我在eclipse中编辑的,但是没有报错,一般来说,没有返回值,eclipse都会有个提示或者报错啥的,但是这个没有, ...

  7. Android报错:The content of the adapter has changed...与Channel is unrecoverably broken and will be disposed的分析与解决办法

    在Android中adapter错误: The content of the adapter has changed but ListView did not receive a notificati ...

  8. Force removing ActivityRecord,app died, no saved state报错的理解

    为什么说理解呢?出现这个问题,我的情景是,在activity里面直接起了一个Thread,线程里面进行了一个繁重的任务,当线程执行完后,这个activity也销毁了,界面显示的任务栈下面的一个活动.百 ...

  9. 从async await 报错Unexpected identifier 谈谈对上下文的理解

    原文首发地址: 先简单介绍下async await: async/await是ES6推出的异步处理方案,目的也很明确:更好的实现异步编程.   详细见阮大神 ES6入门 现在说说实践中遇到的问题:使用 ...

随机推荐

  1. linux centos7 开启 mysql 3306 端口 外网访问 的实践

    第〇步:思路 3306 端口能否被外网访问,主要要考虑: (1)mysql的3306 端口是否开启?是否没有更改端口号? (2)mysql 是否允许3306 被外网访问? (3)linux 是否已经开 ...

  2. python数据结构_递归_汉诺塔问题

    已经不是第一次写这个汉诺塔问题, 其实递归还真是不太好理解, 因为递归这种是想其实有点反人类, 为什么? 因为不太清楚, 写个循环一目了然, 用递归其实要把核心逻辑理清楚, 要不根本没法进行下去 所有 ...

  3. 后ARM时代,嵌入式工程师的自我修养

    1 嵌入式学习的一些概念理解误区 很多嵌入式初学者认为,学嵌入式,就是学习ARM,就是学习开发板.买一块开发板,然后在上面“移植”u-boot.Linux内核,再使用busybox制作一个根文件系统, ...

  4. Docker准备

    1. 引言 Docker是目前最流行的容器技术,是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.是开发人员和系统管理员使用容器开发,部署和运行应用程序的平台.也许我们 ...

  5. 乐字节Java反射之三:方法、数组、类加载器和类的生命周期

    本文承接上一篇:乐字节Java发射之二:实例化对象.接口与父类.修饰符和属性 继续讲述Java反射之三:方法.数组.类加载器 一.方法 获取所有方法(包括父类或接口),使用Method即可. publ ...

  6. Feign【替换默认的feign client】

    说明: feign默认情况下使用的是JDK原始的URLConnection发送的HTTP请求,没有使用到连接池,但是对每个地址会保持长连接,即HTTP的persistence connection.我 ...

  7. ARTS第九周打卡

    Algorithm : 做一个 leetcode 的算法题 /* 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. ...

  8. 机器学习-EM算法的收敛证明

    上一篇开头说过1983年,美国数学家吴建福(C.F. Jeff Wu)给出了EM算法在指数族分布以外的收敛性证明. EM算法的收敛性只要我们能够证明对数似然函数的值在迭代的过程中是增加的 即可: 证明 ...

  9. Thymeleaf 模板使用 Error resolving template "/home", template might not exist or might not be accessible by any of the

    和属性文件中thymeleaf模板的配置相关 1.配置信息 spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix= ...

  10. Java InsertionSort

    Java InsertionSort /** * <html> * <body> * <P> Copyright 1994-2018 JasonInternatio ...