2 votes

routine d'aller se bloquer

Je penche pour l'option "go", ce qui peut être une question stupide.

Je n'arrive pas à comprendre pourquoi l'une de mes routines est bloquée par une autre. Si j'ai bien compris (je peux me tromper), les routines go s'exécutent comme des threads légers indépendants et ne devraient donc pas se bloquer l'une l'autre, à moins que je me sois trompé :)

J'ai collé le code ci-dessous et j'apprécierais toute aide ou conseil pour résoudre ce problème.

package main
import "fmt"
import "time"
import "sync"

func worker( jobs <-chan int, job2 chan<- int) {
    defer wg.Done()
    for j := range jobs {
        fmt.Println("finished job", j)
        time.Sleep(time.Second/2)

        if(j%3==0){
           job2 <- j   
        }  

   } 
   close(job2)
   fmt.Println("channel job2 closed")
 }

func worker2(job2 <-chan int) {
    defer wg.Done()
    for i:= range job2 {
        fmt.Println(i)
        time.Sleep(time.Second*10)
    } 
}

var wg sync.WaitGroup

func main() {

    wg.Add(2)
    jobs := make(chan int)

    job2 := make(chan int)

    go func() {
        for j := 1; j <= 10; j++ {
             jobs <- j
        }
        close(jobs)
        fmt.Println("channel jobs closed")
    }()

    go worker(jobs,job2)
    go worker2(job2)

    wg.Wait()
    fmt.Println("exiting main")     

}

J'obtiens le résultat suivant lorsque j'exécute ce code

finished job 1
finished job 2
finished job 3
finished job 4
3
finished job 5
finished job 6
6
finished job 7
finished job 8
finished job 9
9
finished job 10
channel jobs closed
channel job2 closed
exiting main

Mais je m'attendais à quelque chose comme ça ?

finished job 1
finished job 2
finished job 3
finished job 4
3
finished job 5
finished job 6
finished job 7
finished job 8
finished job 9
finished job 10
channel jobs closed
6
9    
channel job2 closed
exiting main

3voto

Elias Van Ootegem Points 29404

Vos routines sont en quelque sorte bloquantes car les canaux ne sont pas mis en mémoire tampon. Une écriture/lecture sur un canal non tamponné est une opération bloquante. Par conséquent, vos routines doivent, par définition, attendre les unes les autres.

Essentiellement, votre sommeil d'une demi-seconde n'est pas pertinent, car le second travailleur dort pendant 10 secondes. Ces 10 secondes bloqueront les lectures/écritures sur le second canal. Ajoutez un tampon au canal pour contourner ce problème.

J'aimerais également souligner d'autres points :

  • time.Sleep(time.Second/2) ne fonctionnera pas (enfin, si, mais diviser par 3 par exemple ne fonctionnera pas). time.Sleep attend un time.Duration qui est un int64 . Vous devez passer quelque chose comme time.Millisecond * 500 au lieu de
  • Il est mal vu de passer un canal à une routine et de le fermer à partir de la routine qui n'a pas créé le canal. La création et la fermeture des canaux doivent être contenues dans une seule routine. Si ce n'est pas le cas, cela fonctionne, mais la maintenance devient un véritable cauchemar.
  • Regroupez vos importations, au lieu de répéter le import "package" il suffit d'utiliser import ( "package1"\n"package2")
  • N'utilisez pas de globales si vous n'y êtes pas obligé. Créez le groupe d'attente dans la fonction qui démarre toutes les routines, et passez un pointeur vers lui à toutes les routines. Y compris la fonction anonyme, juste pour être sûr (une fois que vous commencez à ajouter des tampons aux canaux, par exemple)
  • Envisagez d'examiner context.Context et le select construire. Vous pouvez créer un context.WithCancel et dans l'écoute sélective ctx.Done() dans toutes les routines. Il est alors possible d'annuler toutes les routines en une seule fois sans avoir à gérer des signaux et à pousser des choses sur un canal d'annulation.

Démonstration

J'ai modifié quelques éléments (principalement la création de canaux, et un peu de nettoyage de code), et j'ai créé un exemple de terrain de jeu. aquí

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X