2016-01-20 24 views
8

Warum reagiert Go beim Schreiben auf einen geschlossenen Kanal?Warum reagiert Go beim Schreiben auf einen geschlossenen Kanal?

Während kann man die value, ok := <-channel Idiom für das Lesen von Kanälen verwenden, und somit kann das ok Ergebnis für das Schlagen mit einem geschlossenen Kanal getestet werden:

// 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) 
} 

Ausgang:

read 2 from channel 
channel is closed 
channel is closed 

Run „aus der Lektüre geschlossener Kanal "on Playground

Das Schreiben in einen möglicherweise geschlossenen Kanal ist komplizierter, weil Go in Panik gerät, wenn Sie einfach versuchen, wri te, wenn der Kanal geschlossen ist:

//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 
} 

Ausgang:

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 

Run "Schreiben in geschlossenem Kanal" auf Playground

Soweit ich weiß, gibt es nicht eine einfachere Idiom zum Schreiben in einen möglicherweise geschlossenen Kanal ohne Panik. Warum nicht? Was ist der Grund für ein solches asymmetrisches Verhalten zwischen Lesen und Schreiben?

+3

Wie würden wir das wissen? Fragen Sie bei Google Golang Gruppe, vielleicht wird einer der Autoren Ihnen antworten. Ich kann mir einen Grund vorstellen. Es ist nur ein gutes Design, um einen Kanal auf Produzentenseite zu schließen. Panicking zwingt Sie, Ihre Anwendung so zu gestalten. – creker

+5

Schließen eines Kanals ist ein Signal, dass es hier keine Werte mehr geben wird. Schreiben in einen geschlossenen Kanal ist ein Programmfehler, der in Panik gerät. – JimB

Antwort

11

Vom Go Language Spec:

Für einen Kanal C wird die eingebaute Funktion close (c) aufzeichnet, dass nicht mehr Werte werden auf dem Kanal gesendet werden. Es ist ein Fehler, wenn c ein Nur-Empfangs-Kanal ist. Das Senden an oder das Schließen eines geschlossenen Kanals führt zu einer Laufzeitpanne . Das Schließen des Nullkanals verursacht auch eine Laufzeitpanik. Nach dem Aufruf von close, und nachdem zuvor gesendete Werte empfangen wurden, geben Empfangsoperationen den Nullwert für den Kanal des Typs ohne Blockierung zurück. Die mehrwertige Empfangsoperation liefert einen empfangenen Wert zusammen mit einer Anzeige, ob der Kanal geschlossen ist.

Wenn Sie in einen geschlossenen Kanal schreiben, wird Ihr Programm in Panik geraten. Du könntest möglicherweise catch this error with recover, wenn du das wirklich willst, aber in einer Situation zu sein, in der du nicht weißt, ob der Kanal, zu dem du schreibst, offen ist, ist normalerweise ein Zeichen für einen Fehler im Programm.

Einige Zitate:

Hier ist eine Motivation:

Ein Kanal "close" ist eigentlich nur ein Sende eines besonderen Wert auf eine Kanal. Es ist ein spezieller Wert, der verspricht, dass keine weiteren Werte gesendet werden. Der Versuch, einen Wert auf einem Kanal zu senden, nachdem er geschlossen wurde, wird in Panik geraten, da das Senden des Werts die Garantie von close verletzen würde. Da ein Schließen nur eine spezielle Art von senden ist, ist es auch nicht erlaubt, nachdem der Kanal geschlossen wurde.ein weitere

ist hier:

Die einzige Verwendung von Kanal nahe an das Lesegerät zu signalisieren, dass es nicht mehr Werte zu kommen. Das macht nur Sinn, wenn es eine einzelne Quelle von Werten gibt oder wenn mehrere Quellen koordinieren. Dort ist kein sinnvolles Programm, in dem mehrere Goroutinen einen Kanal ohne Kommunikation zu schließen. Das würde bedeuten, dass mehrere goroutines wissen, dass es keine weiteren Werte zu senden gibt - wie könnten sie feststellen, wenn sie nicht kommunizieren?

(Ian Lance Taylor)

-

Hier ist eine andere:

einen Kanal gibt sie als Ressource schließen. Es macht keinen Sinn mehr einen Kanal mehrmals zu schließen, als es eine Datei Deskriptor mehrmals zu schließen, oder einen Block von zugewiesenem Speicher mehrere Male freizugeben. Solche Aktionen bedeuten, dass der Code kaputt ist, weshalb das Schließen eines geschlossenen Kanals eine Panik auslöst.

(Rob Pike)

-

Quelle: Go design detail rationale question - channel close