2017-01-21 2 views
1

Je suis coincé dans une situation étrange où l'opération d'écriture sur le canal n'arrive jamais.Ecrivez au canal bloqué pour toujours

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    c := make(chan int) 
    s := make(chan bool) 
    k := make(chan bool) 
    fmt.Println("start") 
    go func() { 
    fmt.Println("routine 1") 
     s <- true 
    }() 
    go func() { 
    fmt.Println("routine 2") 
     for { 
      select { 
      case <-s : 
       for i := 0; i < 3; i++ { 
        fmt.Println("before") 
        c <- i 
        fmt.Println("after") 
       }  
      case <- k : 
       fmt.Println("k ready") 
       break 
      } 
     } 
    }() 

    go func() { 
     fmt.Println("routine 3") 
     for { 
      select { 
       case x := <- c : 
       fmt.Println("x=", x) 
       k <- true 
       fmt.Println("k done") 

      } 
     } 
    }() 

    time.Sleep(1000 * time.Millisecond) 
} 

Et voici la sortie:

start 
routine 1 
routine 2 
before 
routine 3 
x= 0 
after 
before 

Je me demande pourquoi l'écriture aux canaux k blocs, mais la déclaration de journal fmt.Println("k ready") est jamais imprimé.

Voici ce que je pense:

  • go routine 1 écrit vrai canal de
  • go routine 2 écrit 0 à canal c et attend parce que la taille de la mémoire tampon est 0, il ne sera pas en mesure de écrivez '1' à moins que quelqu'un lit le canal c
  • va routine 3 entre dans l'image, lit le canal c (maintenant aller la routine 2 peut écrire à c une fois aller routine 2 CV) imprime la valeur de x. MAINTENANT IL pouvoir écrire sur le canal K, mais cela ne se produit

Selon moi, il devrait être en mesure d'écrire à canal k alors le cas 2 de goroutine doit exécuter et imprimer « k prêt »

Quelqu'un peut-il m'expliquer pourquoi écrire à la chaîne bloquée? Comme une solution, je sais que je peux augmenter la taille de la mémoire tampon du canal c et tout sera imprimé, mais je ne suis pas intéressé par la réparation, à la place, je veux comprendre ce scénario. Un bon blog pour comprendre le cas ci-dessus.

+0

Lien vers le code ci-dessus est [ici] (https://play.golang.org/p/3YL2eoTVn1) –

Répondre

1

Vous avez un blocage.

  • goroutine 1 écrit à s puis se ferme
  • goroutine 2 lectures de s, et écrit à c
  • goroutine 3 lit de c, et écrit à k, et cela bloque parce que rien ne lit de k, parce que la goroutine 2 est bloquée dans l'écriture à k ci-dessus.
  • goroutine 2 écrit c nouveau qui bloque comme goroutine 3 essaie toujours d'écrire à k et est donc pas lire de c

Contrairement à ce que vous dites, vous ne disposez pas d'une taille de mémoire tampon de 1 Vous avez une taille de tampon de zéro (c'est-à-dire un canal non tamponné), donc une écriture bloquera jusqu'à ce que quelque chose se lit. C'est probablement la source de votre malentendu. Par la language specification:

Une nouvelle valeur de canal initialisé peut être effectué en utilisant la fonction intégrée make, qui a le type de canal et une capacité en option comme arguments:

make(chan int, 100) 

La capacité, dans nombre d'éléments, définit la taille du tampon dans le canal.Si la capacité est nulle ou absente, le canal n'est pas tamponné et la communication ne réussit que lorsqu'un émetteur et un récepteur sont prêts. Sinon, le canal est tamponné et la communication réussit sans bloquer si le tampon n'est pas plein (envoie) ou non vide (reçoit). Un canal nul n'est jamais prêt pour la communication.

+0

Merci @abligh pour la réponse, mais il semble que il y a une faute de frappe ou je mal compris votre réponse. Point # 2: écrire sur le canal k se passe dans la routine go 3 De plus, la goroutine 3 ne sera jamais exécutée selon vous? –

+0

Et comprendre le concept de taille de tampon que vous mentionnez mais j'ai dit à tort la taille 1 au lieu de 0, j'ai lu que [ici] (https://blog.golang.org/pipelines). Merci de m'avoir corrigé. –

+0

@sheikhsabeer J'ai fixé l'explication de l'impasse – abligh