這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
很多同學在使用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的設計原則就是簡潔、清晰、不冗餘,用一句流行語來說:My Code,我做主!