2016-01-20 33 views
8

爲什麼Go在寫封閉頻道時恐慌?爲什麼圍棋寫封閉頻道會驚慌?

儘管人們可以使用value, ok := <-channel成語用於從信道讀取,因此,確定的結果可用於擊打一個封閉的通道進行測試:

// reading from closed channel 

package main 

import "fmt" 

func main() { 
    ch := make(chan int, 1) 
    ch <- 2 
    close(ch) 

    read(ch) 
    read(ch) 
    read(ch) 
} 

func read(ch <-chan int) { 
    i,ok := <- ch 
    if !ok { 
     fmt.Printf("channel is closed\n") 
     return 
    } 
    fmt.Printf("read %d from channel\n", i) 
} 

輸出:

read 2 from channel 
channel is closed 
channel is closed 

運行「從讀關閉頻道「在Playground

寫入一個可能關閉的頻道更加複雜,因爲如果您只是試圖wri,Go會驚慌TE當通道被關閉:

//writing to closed channel 

package main 

import (
    "fmt" 
) 

func main() { 
    output := make(chan int, 1) // create channel 
    write(output, 2) 
    close(output) // close channel 
    write(output, 3) 
    write(output, 4) 
} 

// how to write on possibly closed channel 
func write(out chan int, i int) (err error) { 

    defer func() { 
     // recover from panic caused by writing to a closed channel 
     if r := recover(); r != nil { 
      err = fmt.Errorf("%v", r) 
      fmt.Printf("write: error writing %d on channel: %v\n", i, err) 
      return 
     } 

     fmt.Printf("write: wrote %d on channel\n", i) 
    }() 

    out <- i // write on possibly closed channel 

    return err 
} 

輸出:

write: wrote 2 on channel 
write: error writing 3 on channel: send on closed channel 
write: error writing 4 on channel: send on closed channel 

運行「寫入封閉通道」上Playground

據我所知,目前還沒有寫一個簡單的成語進入可能封閉的通道而不會發生恐慌。爲什麼不?讀寫之間這種不對稱行爲背後的原因是什麼?

+3

我們怎麼會知道?向谷歌golang組詢問,也許其中一位作者會回答你。我可以想到一個原因。這只是一個很好的設計來關閉製作方的頻道。恐慌迫使你以這種方式設計你的應用程序。 – creker

+5

關閉一個頻道是一個信號,在這裏將沒有更多的價值。寫入一個封閉的渠道是一個程序錯誤,這恐慌。 – JimB

回答

11

Go Language Spec

對於信道C,在內置函數接近(c)中記錄了沒有更多 值將在該信道上發送。如果c是一個 只接收通道,則是錯誤的。發送或關閉已關閉的通道會導致運行時恐慌。關閉零通道也會導致運行時間恐慌。 在關閉後,以及在接收到之前發送的任何值 後,接收操作將返回通道類型的零值而不會阻塞。多值接收操作 返回接收值以及是否關閉頻道的指示。

如果你寫封閉的頻道,你的程序會驚慌失措。如果你真的想這樣做,你可能會有潛在的catch this error with recover,但是在你不知道你寫的頻道是否開放的情況下,通常是程序中存在錯誤的跡象。

的一些話:

這裏是一個動機:

的信道「關」是真的只是一個在 通道的特殊值的發送。這是一個特殊的價值,承諾沒有更多的價值 被髮送。試圖在已關閉 後關閉頻道上發送值會驚慌,因爲實際發送該值會違反close所提供的 擔保。由於收盤只是一種特殊的發送方式,在頻道關閉後也不允許。

這裏是另一個:

通道靠近的唯一用途是通知閱讀器有 沒有更多的值來。這隻有在存在單個數值來源或多個數據源協調時纔有意義。有 是沒有合理的程序,其中多個goroutines關閉通道 未通信。這意味着多個公用事業公司 會知道沒有更多值要發送 - 他們如何確定如果他們不通信?

(伊恩蘭斯泰勒)

-

這裏是另一個:

關閉一個信道釋放它作爲一種資源。關閉一個通道多次使其關閉一個文件 描述符多次,或者多次釋放一塊分配的內存塊 沒有任何意義。這樣的行爲意味着代碼被破壞,這就是爲什麼關閉一個關閉的通道觸發恐慌。

(羅布·派克)

-

來源:Go design detail rationale question - channel close