【转】Golang 关于通道 Chan 详解
原文: http://blog.csdn.net/netdxy/article/details/54564436
在用 chan 类型时,发生死锁的错误,表面上看不出什么问题
-------------------------------------------------------------------------------------------------------
首先我们来看线程,在golang里面也叫goroutine
在读这篇文章之前,我们需要了解一下并发与并行。golang的线程是一种并发机制,而不是并行。它们之间的区别大家可以上网搜一下,网上有很多的介绍。
下面我们先来看一个例子吧
import("fmt" )funcmain(){go fmt.Println("1")fmt.Println("2") }
在golang里面,使用Go这个关键字,后面再跟上一个函数就可以创建一个线程。后面的这个函数可以是已经写好的函数,也可以是一个匿名函数
funcmain(){var i=3go func(a int) {fmt.Println(a)fmt.Println("1")}(i)fmt.Println("2")}
上面的代码就创建了一个匿名函数,并且还传入了一个参数i,下面括号里的i是实参,a是形参。
那么上面的代码能按照我们预想的打印1、2、3吗?告诉你们吧,不能,程序只能打印出2。下面我把正确的代码贴出来吧
import("fmt""time" ) funcmain(){var i = 3go func(a int) {fmt.Println(a)fmt.Println("1")}(i)fmt.Println("2")time.Sleep(1 * time.Second) }
我只是在最后加了一行让主线程休眠一秒的代码,程序就会依次打印出2、3、1。
那为什么会这样呢?因为程序会优先执行主线程,主线程执行完成后,程序会立即退出,没有多余的时间去执行子线程。如果在程序的最后让主线程休眠1秒钟,那程序就会有足够的时间去执行子线程。
线程先讲到这里,下面我们来看看通道吧。
通道又叫channel,顾名思义,channel的作用就是在多线程之间传递数据的。
创建无缓冲channel
chreadandwrite :=make(chan int)
chonlyread := make(<-chan int) //创建只读channel
chonlywrite := make(chan<- int) //创建只写channel
下面我们来看一个例子:
ch :=make(chan int) ch <- 1go func() {<-chfmt.Println("1")}()fmt.Println("2")
这段代码执行时会出现一个错误:fatal error: all goroutines are asleep - deadlock!
这个错误的意思是说线程陷入了死锁,程序无法继续往下执行。那么造成这种错误的原因是什么呢?
我们创建了一个无缓冲的channel,然后给这个channel赋值了,程序就是在赋值完成后陷入了死锁。因为我们的channel是无缓冲的,即同步的,赋值完成后来不及读取channel,程序就已经阻塞了。这里介绍一个非常重要的概念:channel的机制是先进先出,如果你给channel赋值了,那么必须要读取它的值,不然就会造成阻塞,当然这个只对无缓冲的channel有效。对于有缓冲的channel,发送方会一直阻塞直到数据被拷贝到缓冲区;如果缓冲区已满,则发送方只能在接收方取走数据后才能从阻塞状态恢复。
对于上面的例子有两种解决方案:
1、给channel增加缓冲区,然后在程序的最后让主线程休眠一秒,代码如下:
ch :=make(chan int,1)ch <- 1go func() {v := <-chfmt.Println(v)}()time.Sleep(1 * time.Second)fmt.Println("2")
这样的话程序就会依次打印出1、2
2、把ch<-1这一行代码放到子线程代码的后面,代码如下:
ch :=make(chan int)go func() {v := <-chfmt.Println(v)}()ch <- 1fmt.Println("2")
这里就不用让主线程休眠了,因为channel在主线程中被赋值后,主线程就会阻塞,直到channel的值在子线程中被取出。
最后我们看一个生产者和消费者的例子:
import ("fmt""time" ) func produce(p chan<- int) {for i := 0; i < 10; i++ {p <- ifmt.Println("send:", i)} } func consumer(c <-chan int) {for i := 0; i < 10; i++ {v := <-cfmt.Println("receive:", v)} } func main() {ch := make(chan int)go produce(ch)go consumer(ch)time.Sleep(1 * time.Second) }
在这段代码中,因为channel是没有缓冲的,所以当生产者给channel赋值后,生产者这个线程会阻塞,直到消费者线程将channel中的数据取出。消费者第一次将数据取出后,进行下一次循环时,消费者的线程也会阻塞,因为生产者还没有将数据存入,这时程序会去执行生产者的线程。程序就这样在消费者和生产者两个线程间不断切换,直到循环结束。
下面我们再看一个带缓冲的例子:
import ("fmt""time" ) func produce(p chan<- int) {for i := 0; i < 10; i++ {p <- ifmt.Println("send:", i)} } func consumer(c <-chan int) {for i := 0; i < 10; i++ {v := <-cfmt.Println("receive:", v)} } func main() {ch := make(chan int, 10)go produce(ch)go consumer(ch)time.Sleep(1 * time.Second) }
在这个程序中,缓冲区可以存储10个int类型的整数,在执行生产者线程的时候,线程就不会阻塞,一次性将10个整数存入channel,在读取的时候,也是一次性读取。
转载于:https://www.cnblogs.com/oxspirt/p/7090625.html
【转】Golang 关于通道 Chan 详解相关推荐
- golang程序启动流程详解
golang程序启动流程详解 环境 go1.16.5 linux/amd64 用例 package mainimport "fmt"func main() {fmt.Println ...
- Java NIO学习篇之通道FileChannel详解
定义: FileChannel是Java NIO对应于磁盘等存储设备文件操作的通道. 常用API详解: 获取FileChannel的API /** * 打开一个与文件的连接通道,用于进行文件操作. * ...
- mysql ssh通道_详解如何通过SSH通道来访问MySQL
原标题:详解如何通过SSH通道来访问MySQL 许多时候当要使用Mysql时,会遇到如下情况: 1. 信息比较重要,希望通信被加密. 2. 一些端口,比如3306端口,被路由器禁用. 对第一个问题的一 ...
- Golang map源码详解
Golang的map是用哈希表实现的,在实现性能上非常优秀,这里会主要对map创建.插入.查询.删除以及删除全部的源码做详解,刻意避开了扩容以及迭代相关的代码,后续会用一个新的文章去讲述.Golang ...
- Golang基础知识入门详解
Go语言入门 Go语言入门教程 很多人将 Go 语言 称为 21 世纪的 C 语言,因为 Go 不仅拥有 C 语言的简洁和性能,而且还很好的提供了 21 世纪互联网环境下服务端开发的各种实用特性,让开 ...
- golang包time用法详解
在我们编程过程中,经常会用到与时间相关的各种务需求,下面来介绍 golang 中有关时间的一些基本用法,我们从 time 的几种 type 来开始介绍. 时间可分为时间点与时间段,golang 也不例 ...
- golang中的select详解
注意 监听的case中,没有满足条件的就阻塞 多个满足条件的就任选一个执行 select本身不带循环,需要外层的for default通常不用,会产生忙轮询 break只能跳出select中的一个ca ...
- Golang垃圾回收机制详解
Golang 从第一个版本以来,GC 一直是大家诟病最多的.但是每一个版本的发布基本都伴随着 GC 的改进.下面列出一些比较重要的改动. v1.1 STW v1.3 Mark STW, Sweep 并 ...
- golang——GMP调度模型详解
目录 一.Golang调度器由来 存在问题: 3种协程和线程的关系 二.Golang对协程的处理 协程和goroutine关系 Go的GMP调度模型 P 和 M 何时会被创建 P和M的个数 调度器的设 ...
最新文章
- SQL SERVER 2008 数据恢复错误的解决步骤
- 【Linux】 命令收集
- fpga map测试_一种基于SELECTMAP的可配置且高速的FPGA配置电路及实现方法与流程
- iPhone13真香了?苹果官网被抢崩了,连夜补货!粉色或成爆款..
- java 中的static关键字和final关键字
- python多用户登录_python 多用户登录
- idea设置提示重复代码下去掉波浪线
- UWB与蓝牙AOA定位技术简要对比
- python图书管理实训报告总结_图书管理系统实训报告正文
- 用matlab计算矩阵的权重,如何使用matlab计算加权平均分
- 如何轻松搞定内网摄像头远程运维?EasyNTS上云网关简单三步实现设备公网远程控制、远程配置
- 狭义相对论推导过程中的数学悖论--有没有人能解释下?
- js中this指向学习总结
- 利用python下载视频
- 计算机程序设计员国家职业资格三级(高级)操作技能考核试卷-四川考场
- 计算机专业调剂化学专业,汕头大学计算机化学专业2015年考研调剂信息
- node生成图形验证码
- 前端flyUI的方法使用注意事项
- 云服务器测速脚本_Linux VPS服务器带宽测速脚本:Speedtest Linux进行网络测速方法...
- 汉明窗口Hamming Window
热门文章
- oracle数据库中could not get next sequence value的解决
- 吴恩达深度学习 —— 2.14 向量化逻辑回归的梯度输出
- Excel2010--在指定的范围内添加随机数
- Unity 4 3 制作一个2D横版射击游戏
- 各种排序算法比较--2015年7月23日22:33:43v1.0版
- 什么样的产品可以成功?
- 浏览器测试基本跑分网站
- c语言实验五函数答案,C语言程序设计实验五 参考答案.doc
- java 控制 sortedset_Java集合的checkedSortedSet()方法和示例
- 使用java连接ftp服务器_Java如何连接到FTP服务器?