web-dev-qa-db-fra.com

Vérification si une chaîne a une valeur prête à être lue, à l'aide de Go

Comment vérifier si une chaîne a une valeur à lire?

Je ne veux pas bloquer lors de la lecture d'une chaîne. Je veux voir s'il a une valeur. S'il en a un, je le lirai. S'il n'en a pas (encore), je ferai autre chose et je reviendrai plus tard.

31
gonewbgo

AVERTISSEMENT : Ce n'est plus exact, voir la réponse ci-dessous.

De la documentation:

Si une expression de réception est utilisée dans une affectation ou une initialisation du formulaire

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch

l'opération de réception devient non bloquante. Si l'opération peut se poursuivre, la variable booléenne ok sera définie sur true et la valeur stockée dans x; sinon ok est défini sur false et x est défini sur la valeur zéro pour son type

5
nos

La seule opération non bloquante que je connaisse pour lire à partir d'un canal est à l'intérieur d'un bloc de sélection ayant un cas par défaut:

    select {
    case x, ok := <-ch:
        if ok {
            fmt.Printf("Value %d was read.\n", x)
        } else {
            fmt.Println("Channel closed!")
        }
    default:
        fmt.Println("No value ready, moving on.")
    }

Veuillez essayez le non-blocage ici

Remarque sur les réponses précédentes: l'opérateur de réception lui-même est maintenant une opération de blocage , à partir de Go 1.0.3. Le spec a été modifié. Veuillez essayez le blocage ici (blocage)

80
Deleplace

Si vous faites cela souvent, ce n'est probablement pas un excellent design et vous feriez mieux de faire apparaître un autre goroutine pour faire le travail que vous prévoyez de faire lorsqu'il n'y a rien à lire sur la chaîne. La nature synchrone/bloquante des canaux de Go facilite la lecture et le raisonnement du code, tandis que le planificateur et les goroutines bon marché signifient que les appels asynchrones sont inutiles car les goroutines en attente prennent très peu de ressources.

7
Jessta

Vous ne le faites pas, du moins pas pour les canaux synchrones (sans tampon). Il n'y a aucun moyen de savoir si une valeur est en attente sans demander de prendre la valeur du canal.

Pour les canaux tamponnés, vous pouvez techniquement utiliser la fonction len pour faire ce que vous décrivez, mais vous ne devriez vraiment, vraiment pas. Votre technique n'est pas valide.

La raison en est qu'il représente une condition de concurrence. Étant donné le canal ch, votre goroutine pourrait voir que len (ch)> 0 et conclure qu'il y a une valeur en attente. Cependant, il ne peut pas conclure qu'il peut lire à partir du canal sans le bloquer - un autre goroutine peut vider le canal entre le moment où vous vérifiez len et le moment où votre opération de réception s'exécute.

Aux fins que vous avez décrites, utilisez select avec un cas par défaut comme l'a montré Ripounet.

7
Sonia

Malheureusement, les réponses précédentes sont incorrectes. Le spec indique clairement que vous POUVEZ utiliser les canaux de cette façon en utilisant la fonction len (), mais seulement si vous avez spécifié la capacité du canal - la longueur de la mémoire tampon pour un canal tout en le faisant. Si vous avez omis une capacité de canal en le faisant - les opérations du canal sont toujours bloquantes.

5