从两道题看go channel的用法
在知乎看到有人分享了几道笔试题,自己总结了一下其中与channel有关的题目。全部题目在这里:
题目
5、请找出下面代码的问题所在。
func main() {
ch := make(chan int, 1000)
// goroutine1
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
}()
// goroutine2
go func() {
for {
a, ok := <-ch
if !ok {
fmt.Println("close")
return
}
fmt.Println("a: ", a)
}
}()
close(ch)
fmt.Println("ok")
time.Sleep(time.Second * 100)
}
8、请说出下面代码哪里写错了
func main() {
abc := make(chan int, 1000)
for i := 0; i < 10; i++ {
abc <- i
}
// receiver goroutine
go func() {
for {
a := <-abc
fmt.Println("a: ", a)
}
}()
close(abc)
fmt.Println("close")
time.Sleep(time.Second * 100)
}
解释
首先要明确这两个要点:
- 向一个已经关闭的channel发送数据是会抛panic的,但是从一个已关闭的channel接收数据并不会抛panic,而是得到channel数据类型的零值。
- 同一个段程序每次启动后goruntine的调度不一定相同,所以goroutine的执行顺序有可能不一样。
先看第一题,代码运行时会抛出panic:
panic: send on closed channel
这是因为goroutine1 还没把i 发送给ch,ch 就在main函数中被close,当把i 发送到ch 时就抛出了panic。同理goroutine2 中从已关闭的ch 中接收数据时ok 会返回false,然后就return了。而且由于goroutine 的执行顺序不一样,输出close、ok、panic的顺序也会不一样,有兴趣的话可以自己跑几次。
那么如果想让程序正常输出应该怎么改呢,下面是其中一种方法:
func main() {
ch := make(chan int, 1000)
// goroutine1
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
// 只有一个goroutine向ch发送数据,可以考虑在这个goroutine中关闭。
close(ch)
}()
// goroutine2
go func() {
for {
a, ok := <-ch
if !ok {
fmt.Println("close")
return
}
fmt.Println("a: ", a)
}
}()
fmt.Println("ok")
time.Sleep(time.Second * 100)
}
再来看第二题,运行时输出完0—9后会一直输出0,直到sleep的时间结束。这是因为在把0—9发送给abc 后abc 就被关闭了,receiver goroutine 在接收完0—9后没有跳出for 循环,而是一直从被关闭的abc 中接收数据,所以接收到的是abc 的零值——0。
有一种最简单的办法可以改正这个程序:
func main() {
abc := make(chan int, 1000)
for i := 0; i < 10; i++ {
abc <- i
}
go func() {
// 使用for-range,abc被关闭后会自动退出for循环。
for a := range abc {
fmt.Println("a: ", a)
}
}()
close(abc)
fmt.Println("close")
time.Sleep(time.Second * 10)
}
总结
使用channel时,
- 如果只有一个goroutine 向channel发送数据,可以在该goroutine 中close channel。当有多个goroutine 向channel 发送元素时close channel 的方法可以参考这篇文章:
- 用for-range 从channel 中接收数据代码简洁而且基本没有副作用。
扩展阅读
关于goroutine是如何调度的,可以参考这篇文章:
References
http://colobu.com/2016/04/14/Golang-Channels/
从两道题看go channel的用法的更多相关文章
- 从一道题看线程安全--牛客网Java基础题
从一道题看线程安全 Java中的线程安全是什么: 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的 ...
- /*透明度设置的两种方式,以及hover的用法,fixed,(relative,absolute)这两个一起用*/
<!DOCTYPE html> /*透明度设置的两种方式,以及hover的用法,fixed,(relative,absolute)这两个一起用*/ <html lang=" ...
- Golang | 简介channel常见用法,完成goroutin通信
今天是golang专题的第14篇文章,大家可以点击上方的专辑回顾之前的内容. 今天我们来看看golang当中另一个很重要的概念--信道.我们之前介绍goroutine的时候曾经提过一个问题,当我们启动 ...
- 一文看懂ConstraintLayout的用法
ConstraintLayout 相对于 RelativeLayout来说性能更好,布局上也更加灵活.在最新的Google Android开发文档中是推荐使用 ConstraintLayout的,下面 ...
- php封装协议的两道题
这几天终于刷完了自己说是要刷完的那几道题,赶紧写几篇博客记录.. 1. 先看看这个网站:https://blog.csdn.net/qq_41289254/article/details/81388 ...
- 从一道题看js的拆箱操作
前段时间看到一道题,如下:([][[]]+[])[+![]]+([]+{})[!+[]+![]]问最终打印结果,然后简单了解一下js的装箱,拆箱操作. 基本 装箱操作: 就是将基本类型(String, ...
- 最近这两天看了关于H5游戏开发的一个教程,实践很短暂,看了很多理论的东西,现在呢也只是想回忆回忆关于EUI的部分知识吧
首先我了解了什么是Egret: Egret中文就是白鹭的意思,Egret是一套H5游戏开发的软件.(纯粹属于个人理解) 其次我对以下几款软件的相关知识做了些了解: Egret Engine(引擎),E ...
- Codeforces 460 DE 两道题
D Little Victor and Set 题目链接 构造的好题.表示是看了题解才会做的. 假如[l,r]长度不超过4,直接暴力就行了. 假如[l,r]长度大于等于5,那么如果k = 1,显然答案 ...
- js的call() ,apply() 两种方法的区别和用法,最白话文的解释,让枯燥滚粗!
百度了一圈calll()函数和apply()函数,感觉还是糊里糊涂 正好我前几天刚又重新翻了一遍 那本 600多页 的圣经书,我习惯时不时的去打下基础,只是为了用来装逼,给人讲解....(我是有多蛋疼 ...
随机推荐
- WPF进阶之接口(3):INotifyPropertyChanged,ICommand
INotifiPropertyChanged . 作用:向客户端发出某一属性值已更改的通知.该接口包含一个PropertyChanged事件成员(MSDN的解释) INotifyPropertyCha ...
- 应用开发之Asp.net
本章简言 上一章中笔者讲到关于Linq和EF的用法.并以hibernate来进行讲解.那么本章笔者来讲一下C#的Asp.Net.即是在B/S模式下开发.现在企业大部分的业务都是面向B/S模式的.所以对 ...
- Zabbix-3.0.x使用OneAlert发送告警
导读 OneAlert 是国内首个 SaaS 模式的云告警平台,集成国内外主流监控/支撑系统,实现一个平台上集中处理所有 IT 事件,提升 IT 可靠性.它能以史上第二快的速度,对事件进行智能的组织. ...
- 《转》武汉的IT公司
本文转载自sherry020406前段时间看到版上有同学问在武汉找工作的情况,我谈谈去年找工作时碰到或者听到的一些企业,希望以下内容对想去武汉工作的同学有帮助,也算是对job版的回报.有些公司的情况可 ...
- 【BZOJ4872】[Shoi2017]分手是祝愿 数学+期望DP
[BZOJ4872][Shoi2017]分手是祝愿 Description Zeit und Raum trennen dich und mich. 时空将你我分开.B 君在玩一个游戏,这个游戏由 n ...
- Ubuntu安装atom
sudo add-apt-repository ppa:webupd8team/atom sudo apt-get update sudo apt-get install atom 安装的时如果报错, ...
- Windows MFC 打开文本
MFC的CFileDialog自动封装了文件相关的对话框,提供一种简单的文件打开和文件存盘对话框功能. 要使用CFileDialog类,首先要构造一个对象, 项目实例: CFileDialog fil ...
- kibana5.6 源码分析以--环境搭建&技术准备
Kibana是一个开源的分析与可视化平台,设计出来用于和Elasticsearch一起使用的.你可以用kibana搜索.查看.交互存放在Elasticsearch索引里的数据,使用各种不同的图表.表格 ...
- http协议------>概述和动手实践认识Http协议
http协议是用来定义客户端和web服务器通讯格式 浏览器与服务器的交互过程 是tcp/ip的应用层 版本:http/1.0(客户端和web服务器建立连接后只能访问一个web资源) http/1. ...
- 转发URL请求
如何用Netty实现一个轻量级的HTTP代理服务器 - Newland - 博客园 https://www.cnblogs.com/jietang/p/8926325.html 现在迫切希望有一个HT ...