很多同学在使用channel时都遇到过这种情况:Panic问题,相信大家对于这种设计也吐槽了不少吧?这篇文章我们就来扒一扒这样设计的初衷。
潜在的Panic主要有两种: 重复close一个channel,向已经closed的channel继续发送消息。
最懒的解决办法就是通过recover来简单粗暴的恢复,可是这就违背了设计者的初衷。对于channel c来说,内置的close函数表明了不会再有任何值发送到c,重复关闭或者向已经关闭的c发送任何消息都会导致runtime panic,关闭nil channel也会导致panic。
这里有个问题,如果c关闭了,继续从c读取消息会怎么样?不用担心,至少不会有panic发生。首先是从c中读取之前发送但是还没有被接收的消息,当这类消息接收完了,之后接受到的消息都是对应channel类型的零值,要注意的是,从一个关闭的channel中接收消息是完全不会阻塞的!!当然,我们可以通过接收操作的第二个参数来判断channel是否已经关闭,如果关闭,就不要继续接收消息了。
回到上面的recover话题,为什么不提议这么做呢,因为一旦这么做,就意味着你对自己的程序设计时存在什么潜在的bug根本就不清楚,只想着通过异常处理这种最粗暴的方式来解决。向一个还在打开的channel发送消息,就是设计上可能存在的bug!
其实从底层来说,close也是channel上的一次消息发送操作,只不过发送的是一个特殊的关闭消息,该消息就是承诺给系统,该channel绝对不会再收到任何消息。如果继续发送消息,就会违背这种承诺。同时,由于close也是消息发送,因此重复close也会导致panic。
大家应该都知道这个idiom:只应该由发送方来关闭channel。那同学们肯定也有疑问,那如果同一个channel有多个发送方呢?这个就是我们程序设计的问题了,如果多个发送方都要求去关闭channel,但是彼此之间根本就不沟通,那就是有问题的:因为这种情况下,如果某个发送方要关闭channel,却不通知其它发送方,那就存在很大的潜在bug了,至少关闭一个公有频道,需要得到大家的认可才行!
这里附上Rob Pike大神的一段原文翻译:
关闭一个channel就是释放一个资源。多次关闭一个channel就像多次关闭文件描述符、多次释放内存块一样,都是没有任何意义的。这些操作都意味着代码是有问题的,这也是为什么我们设计时就强制产生了panic。
看看,大神果然是大神,一句话就阐述清了问题:都是设计和代码问题!因此让自己的设计和代码清晰明朗起来是非常重要的,能不用recover解决问题就不用。
总之,Go的设计原则就是简洁、清晰、不冗余,用一句流行语来说:我的代码,我做主!
有疑问加站长微信联系(非本文作者)