在《The way to go - 14.2 协程间的信道》教程中看到了关于chan阻塞的相关内容,自己写代码对通道的阻塞特性做了一点测试。

贴之前先复习一下知识点。以下是我自己的总结,如果不对还请网友指正。

1,golang的通道(chan)可分为不带缓存的通道和带缓存的通道。用make函数创建通道的时候,如果不指定缓存大小,创建的就是不带缓存的通道。

2,通道是一个类型化消息队列。这句话有两个意思,一是在创建通道时,需要指定通道中传输什么类型的数据。例如var c chan int,这句代码声明了一个名字叫c的通道,这个通道只能传输int类型的数据。int也可以换成空接口(interface{})类型,但数据接收端在使用数据时就需要进行数据类型判定。这句话的第二个意思是通道是一个先进先出(FIFO)的结构,放入通道的数据具有时序性。

3,向通道中放入数据的一端可以称为生产者,从通道获取数据的一端可以称为消费者。

c := make(chan int)    // 不带缓存的通道
c <- 100               // 生产
recv := <- c           // 消费

4,不带缓存的通道,在通道任一一端没有准备就绪之前,另一端就会产生阻塞。下面用The way to go的例子来说明。

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

上面这段代码在执行的时候会产生死锁。在main函数中先执行向out通道中放入数据,再启动go协程。在向out通道放入数据时,通道的消费者还未准备就绪(粗暴一点解释就是,还没有执行到消费数据的代码),所以程序会一直在out <- 2这个地方一直阻塞,不会执行go f1(out)。不执行go f1(out)的结果就是,go协程中的消费者端就永远不会就绪。这段代码只需要将启动go协程和向通道放入数据的代码前后调换下位置,就可以解决死锁。

接下来就用两个稍微复杂一点的程序来说明通道阻塞。

例1:


func main() {// 创建不带缓存的通道c := make(chan int)// 启动go协程并将通道c作为参数传入go myRoutine(c)// 向通道中写入数据,并在写入成功后打印写入成功的消息for i := 0; i < 10; i++ {c <- ifmt.Printf("Sent %v to chan\n", i)}// 打印程序结束时间fmt.Printf("End process at %v", time.Now())
}func myRoutine(c chan int) {// 打印go协程启动时间fmt.Printf("Start goroutine at %v\n", time.Now())var msg intfor {time.Sleep(4 * 1e9)// 从通道中接收数据msg = <-ctime.Sleep(1 * 1e9)// 打印接收到的数据和接收时间fmt.Printf("Get msg %d from chan at %v\n", msg, time.Now())}
}

程序输出如下:

Start goroutine at 2021-10-01 10:41:45.9047405 +0800 CST m=+0.002146401
Sent 0 to chan at main method.
Get msg 0 from chan at 2021-10-01 10:41:50.918935 +0800 CST m=+5.016340901
Sent 1 to chan at main method.
Get msg 1 from chan at 2021-10-01 10:41:55.9351083 +0800 CST m=+10.032514201
Sent 2 to chan at main method.
Get msg 2 from chan at 2021-10-01 10:42:00.9482089 +0800 CST m=+15.045614801
Sent 3 to chan at main method.
Get msg 3 from chan at 2021-10-01 10:42:05.9627741 +0800 CST m=+20.060180001
Sent 4 to chan at main method.
Get msg 4 from chan at 2021-10-01 10:42:10.9670808 +0800 CST m=+25.064486701
Sent 5 to chan at main method.
Get msg 5 from chan at 2021-10-01 10:42:15.9917451 +0800 CST m=+30.089151001
Sent 6 to chan at main method.
Get msg 6 from chan at 2021-10-01 10:42:21.0252843 +0800 CST m=+35.122690201
Sent 7 to chan at main method.
Get msg 7 from chan at 2021-10-01 10:42:26.0522605 +0800 CST m=+40.149666401
Sent 8 to chan at main method.
Get msg 8 from chan at 2021-10-01 10:42:31.0667841 +0800 CST m=+45.164190001
Sent 9 to chan at main method.
End process at 2021-10-01 10:42:35.0850043 +0800 CST m=+49.182410201

从上面的输出可以看出在执行到msg = <-c这句代码之前(消费者端就绪之前),生产者端是处于发送等待状态(阻塞)的。消费者端一旦准备就绪,生产者端马上向通道中写入数据。

例2:

func main() {c := make(chan int)go myRoutine(c)time.Sleep(5 * 1e9)for i := 0; i < 5; i++ {c <- ifmt.Printf("Sent %v to chan at main method.\n", i)time.Sleep(5 * 1e9)}fmt.Printf("End process at %v", time.Now())
}func myRoutine(c chan int) {fmt.Printf("Start goroutine at %v\n", time.Now())var msg intfor {fmt.Printf("Ready to get msg from chan at %v\n", time.Now())msg = <-cfmt.Printf("Get msg %d from chan at %v\n", msg, time.Now())}
}

程序输出如下:

Start goroutine at 2021-10-01 10:55:51.5484438 +0800 CST m=+0.002574401
Ready to get msg from chan at 2021-10-01 10:55:51.5609746 +0800 CST m=+0.015105201
Sent 0 to chan at main method.
Get msg 0 from chan at 2021-10-01 10:55:56.5649773 +0800 CST m=+5.019107901
Ready to get msg from chan at 2021-10-01 10:55:56.5649773 +0800 CST m=+5.019107901
Sent 1 to chan at main method.
Get msg 1 from chan at 2021-10-01 10:56:01.5794729 +0800 CST m=+10.033603501
Ready to get msg from chan at 2021-10-01 10:56:01.5794729 +0800 CST m=+10.033603501
Sent 2 to chan at main method.
Get msg 2 from chan at 2021-10-01 10:56:06.5900095 +0800 CST m=+15.044140101
Ready to get msg from chan at 2021-10-01 10:56:06.5900095 +0800 CST m=+15.044140101
Sent 3 to chan at main method.
Get msg 3 from chan at 2021-10-01 10:56:11.6087279 +0800 CST m=+20.062858501
Ready to get msg from chan at 2021-10-01 10:56:11.6087279 +0800 CST m=+20.062858501
Sent 4 to chan at main method.
Get msg 4 from chan at 2021-10-01 10:56:16.6128717 +0800 CST m=+25.067002301
Ready to get msg from chan at 2021-10-01 10:56:16.6128717 +0800 CST m=+25.067002301
End process at 2021-10-01 10:56:21.6246286 +0800 CST m=+30.078759201

从上面的输出可以看出在执行到main函数中c <- i这句代码之前(生产者端就绪之前),消费者端是处于发送等待状态(阻塞)的。生产者端一旦准备就绪,消费者端马上从通道中取得数据,并开始执行之后的打印语句。

Golang的chan阻塞测试相关推荐

  1. 制坯系列-Golang专题-chan

    <制坯系列-Golang专题>:chan作为协程之间通信的重要方式,是替代内存共享的最佳通信方式,本文对基本原理和关键知识点做简单介绍 chan底层数据结构 type hchan stru ...

  2. golang 学习 - chan以及chan的一下用例

    golang 学习 - chan 1. 通道 // _通道_ 是连接多个 Go 协程的管道.你可以从一个 Go 协程 // 将值发送到通道,然后在别的 Go 协程中接收.package mainimp ...

  3. golang的chan(管道)

    golang的chan翻译成中文就是管道,顾名思义,就是管道的一端用来读,另一端用来写,这与write和read函数的性质是非常相似的,比如说管道中没数据,就会发生读阻塞,管道中数据是满的,就会发生写 ...

  4. GoLang之go test测试

    文章目录 GoLang之go test测试 1.介绍 2.函数 3.测试函数格式 3.1格式 3.2失败示例 3.3成功示例1 3.4成功示例2 3.5成功示例3 3.6成功实例4 4.基准函数 4. ...

  5. go/golang语言编写压力测试

    go/golang语言编写压力测试 近期复习了一下go,发现go的压力测试是个好东西.记录一下怎么使用. 压力测试用来检测函数(方法)的性能,和编写单元功能测试的方法类似,此处不再赘述,但需要注意以下 ...

  6. golang笔记09--go语言测试与性能调优

    golang笔记09--go语言测试与性能调优 1 介绍 2 测试与性能调优 2.1 测试介绍 2.2 代码覆盖率和性能测试 2.3 使用pprof进行性能调优 2.4 测试http服务器(上) 2. ...

  7. golang mysql 非阻塞_Golang 实现轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库...

    gev 轻量.快速的 Golang 网络库 gev 是一个轻量.快速的基于 Reactor 模式的非阻塞 TCP 网络库,底层并不使用 golang net 库,而是使用 epoll 和 kqueue ...

  8. golang管道chan

    package mainimport ("fmt""time" )func main() {//test2()test4()time.Sleep(time.Se ...

  9. golang基础-chan的select操作、定时器操作、超时控制、goroutine中使用recover

    chan的只读和只写 a.只读chan的声明 Var 变量的名字 <-chan int Var readChan <- chan int b. 只写chan的声明 Var 变量的名字 ch ...

  10. Golang实践录:测试框架

    这篇集中记录一下测试相关的内容. 背景 创建工程库代码,方便重用.重用方式可使用函数,也可直接引用文件. 完成函数,可在 main 函数中调用进行测试.也可以使用 test 框架进行. 在大型项目中, ...

最新文章

  1. java8 wordcount_Spark2.x与Java8下WordCount示例
  2. R语言使用ggplot2包使用geom_violin函数绘制分组小提琴图(配置填充色调色板、brewer调色板、灰度比例)实战
  3. spring boot模板引擎thymleaf用法详解
  4. vuecli4 启动_vue 常见命令 (启动 部署)
  5. 少儿计算机兴趣小组活动记录,2013年度儿童画兴趣小组活动记录Word编辑
  6. jq的插件 vue中引用_详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
  7. Tomcat启动报Error listenerStart错误
  8. 卢伟冰:这几天黑稿明显增多了 法务又要忙了
  9. 清退117名博士、119名硕士!研究生“严出”成人才培养大趋势
  10. dat关闭某进程_电脑程序卡住怎么办?结束进程只需要这三个键
  11. 基于DSP的主动降噪开发之三(CCS软件学习)
  12. ios13短信如何转移到android,iOS13加入全新数据迁移功能,无需网络也能转移旧手机数据...
  13. python开发指法练习软件_猿编程电脑端
  14. UML一篇文章就学通!
  15. 【quartus】packed unpacked array
  16. oracle通信通道的文件结尾_“ORA-03113: 通信通道的文件结尾”报错处理
  17. 计算机桌面按哪个键锁定呀,计算机锁定屏幕快捷键-一种锁定计算机屏幕的快捷方式...
  18. 高级语言程序设计(实验四)
  19. 数据结构与算法基础——重要知识点截图【青岛大学-王卓版】
  20. AVPlayer使用学习

热门文章

  1. 街景影像分析入门(二)无需秘钥,抓取百度街景影像
  2. kill word out e ef en em
  3. 用友U8 业务单据打印机设置
  4. 解决“error C1083: 无法打开包括文件: “HPSocket.h”: No such file or directory”
  5. 腾讯战华为:一场「渠道」之争背后,游戏行业变天了
  6. 支付宝登陆泰国最大免税店King Power可扫码支付
  7. wed基础和http
  8. iphone个系列尺寸_iPhone9只是套模iPhone8,这些才是iPhone经典款,你用过哪些?
  9. hdu5294Tricks Device【最短路+网络流】
  10. ASP.NET Core 自定义中间件