web-dev-qa-db-fra.com

Pourquoi Go panique-t-il en écrivant sur une chaîne fermée?

Pourquoi Go panique-t-il en écrivant sur une chaîne fermée?

Alors que l'on peut utiliser le value, ok := <-channel idiome pour la lecture des canaux, et donc le résultat correct peut être testé pour frapper un canal fermé:

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

Production:

read 2 from channel
channel is closed
channel is closed

Exécutez "lecture depuis un canal fermé" sur Playground

Écrire sur un canal éventuellement fermé est plus compliqué, car Go paniquera si vous essayez simplement d'écrire lorsque le canal est fermé:

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

Production:

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

Exécutez "l'écriture sur le canal fermé" sur Playground

Pour autant que je sache, il n'y a pas d'idiome plus simple pour écrire dans un canal éventuellement fermé sans paniquer. Pourquoi pas? Quel est le raisonnement derrière un tel comportement asymétrique entre lecture et écriture?

14
Everton

De la Go Language Spec :

Pour un canal c, la fonction intégrée close (c) enregistre qu'aucune autre valeur ne sera envoyée sur le canal. C'est une erreur si c est un canal de réception uniquement. L'envoi ou la fermeture d'un canal fermé provoque une panique au moment de l'exécution. La fermeture du canal nul provoque également une panique au moment de l'exécution. Après avoir appelé close et après avoir reçu toutes les valeurs précédemment envoyées, les opérations de réception renverront la valeur zéro pour le type de canal sans blocage. L'opération de réception à valeurs multiples renvoie une valeur reçue avec une indication de la fermeture ou non du canal.

Si vous écrivez sur une chaîne fermée, votre programme paniquera. Vous pourriez potentiellement attraper cette erreur avec récupérer si vous voulez vraiment le faire, mais être dans une situation où vous ne savez pas si le canal sur lequel vous écrivez est ouvert est généralement le signe d'un bug dans le programme.

Quelques citations:

Voici une motivation:

Un canal "fermé" n'est en réalité qu'un envoi d'une valeur spéciale sur un canal. Il s'agit d'une valeur spéciale qui promet qu'aucune autre valeur ne sera envoyée. Tenter d'envoyer une valeur sur un canal après sa fermeture paniquera, car l'envoi de la valeur violerait la garantie fournie par close. Comme une fermeture n'est qu'un type spécial d'envoi, elle n'est pas non plus autorisée après la fermeture du canal.

En voici une autre:

La seule utilisation de la fermeture de canal est de signaler au lecteur qu'il n'y a plus de valeurs à venir. Cela n'a de sens que lorsqu'il existe une seule source de valeurs ou lorsque plusieurs sources se coordonnent. Il n'y a pas de programme raisonnable dans lequel plusieurs goroutins ferment un canal sans communiquer. Cela impliquerait que plusieurs goroutines sauraient qu'il n'y a plus de valeurs à envoyer - comment pourraient-elles le déterminer si elles ne communiquent pas?

(Ian Lance Taylor)

-

En voici une autre:

La fermeture d'un canal le libère en tant que ressource. Il n'est pas plus logique de fermer un canal plusieurs fois que de fermer un descripteur de fichier plusieurs fois ou de libérer un bloc de mémoire allouée plusieurs fois. De telles actions impliquent que le code est cassé, c'est pourquoi la fermeture d'un canal fermé déclenche une panique.

(Rob Pike)

-

Source: Aller à la question de justification du détail de la conception - fermeture du canal

19
Justlike