在知乎看到有人分享了几道笔试题,自己总结了一下其中与channel有关的题目。全部题目在这里:

https://zhuanlan.zhihu.com/p/35058068

题目

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 的方法可以参考这篇文章:

    https://www.jianshu.com/p/d24dfbb33781

  • 用for-range 从channel 中接收数据代码简洁而且基本没有副作用。

扩展阅读

关于goroutine是如何调度的,可以参考这篇文章:

https://blog.csdn.net/liangzhiyang/article/details/52669851

References

http://colobu.com/2016/04/14/Golang-Channels/

从两道题看go channel的用法的更多相关文章

  1. 从一道题看线程安全--牛客网Java基础题

    从一道题看线程安全 Java中的线程安全是什么: 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的 ...

  2. /*透明度设置的两种方式,以及hover的用法,fixed,(relative,absolute)这两个一起用*/

    <!DOCTYPE html> /*透明度设置的两种方式,以及hover的用法,fixed,(relative,absolute)这两个一起用*/ <html lang=" ...

  3. Golang | 简介channel常见用法,完成goroutin通信

    今天是golang专题的第14篇文章,大家可以点击上方的专辑回顾之前的内容. 今天我们来看看golang当中另一个很重要的概念--信道.我们之前介绍goroutine的时候曾经提过一个问题,当我们启动 ...

  4. 一文看懂ConstraintLayout的用法

    ConstraintLayout 相对于 RelativeLayout来说性能更好,布局上也更加灵活.在最新的Google Android开发文档中是推荐使用 ConstraintLayout的,下面 ...

  5. php封装协议的两道题

    这几天终于刷完了自己说是要刷完的那几道题,赶紧写几篇博客记录.. 1.  先看看这个网站:https://blog.csdn.net/qq_41289254/article/details/81388 ...

  6. 从一道题看js的拆箱操作

    前段时间看到一道题,如下:([][[]]+[])[+![]]+([]+{})[!+[]+![]]问最终打印结果,然后简单了解一下js的装箱,拆箱操作. 基本 装箱操作: 就是将基本类型(String, ...

  7. 最近这两天看了关于H5游戏开发的一个教程,实践很短暂,看了很多理论的东西,现在呢也只是想回忆回忆关于EUI的部分知识吧

    首先我了解了什么是Egret: Egret中文就是白鹭的意思,Egret是一套H5游戏开发的软件.(纯粹属于个人理解) 其次我对以下几款软件的相关知识做了些了解: Egret Engine(引擎),E ...

  8. Codeforces 460 DE 两道题

    D Little Victor and Set 题目链接 构造的好题.表示是看了题解才会做的. 假如[l,r]长度不超过4,直接暴力就行了. 假如[l,r]长度大于等于5,那么如果k = 1,显然答案 ...

  9. js的call() ,apply() 两种方法的区别和用法,最白话文的解释,让枯燥滚粗!

    百度了一圈calll()函数和apply()函数,感觉还是糊里糊涂 正好我前几天刚又重新翻了一遍 那本 600多页 的圣经书,我习惯时不时的去打下基础,只是为了用来装逼,给人讲解....(我是有多蛋疼 ...

随机推荐

  1. 选择LoadRunner Protocol的两大定律

    选择LoadRunner Protocol的两大定律 确定性能测试脚本录制时使用的协议类型经常是一个容易引起误会的问题.很多刚刚接触到性能测试的同行常常会想当然地根据开发语言等来决定协议的选取,导致录 ...

  2. Docker 使用及常用命令

    https://yeasy.gitbooks.io/docker_practice/content/image/dockerfile/expose.html docker practice 资料 -- ...

  3. 【RF库测试】Exit For Loop 相关

    1.Exit For Loop If:满足条件时,跳出循环,后面的循环不再执行 2.Continue For Loop If:满足条件时,跳出本次循环,继续执行后面的循环

  4. Python学习笔记4—列表List

    列表定义 Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. >>> a=['] >>> type(a) &l ...

  5. GitHub Pages站点官方宣布开始使用HTTPS

    导读 数百万人依靠GitHub Pages,将其作为他们的网站主机,除此之外,还有数百万人每天访问这些网站.为了更好地保护到GitHub Pages站点的通讯,也为了鼓励在因特网上更广泛地采用HTTP ...

  6. poj_3259 负权和环

    题目大意 N个点,M条双向路径,W条单向路径.从双向路径的一端到另一端所花费时间为正值,从单向路径的源点到终点所花时间为负值.问是否存在一条从A出发,再回到A的回路,满足回到A的时间小于出发时间. 题 ...

  7. jquery中return false的作用

    jquery中的return false既阻止默认事件,又阻止冒泡: 在原生的js中,return false只有一个功能,那就是阻止默认事件. <!DOCTYPE html> <h ...

  8. angular4 checkbox复选框的全选,反选及个别选择

    <label><input type="checkbox" name="" [(ngModel)]="master"> ...

  9. html 事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。

    看一个简单的例子: html: <head> <meta charset="UTF-8"> <title>Document</title& ...

  10. jsp+servlet+mvc模式图

    在我们的开发中,最常用的开发模式莫过于MVC模式,即M--MODEL.V--View.C--Controller,这样不仅可以方便开发人员分工协作,提高开发效率,增强程序的可维护性和拓展性,而且利用C ...