2017-07-02 5 views
1

Ich arbeite an einem Konsolen-Musik-Player in Go. Immer wenn der Benutzer ein Album auswählt und wiedergibt, starte ich eine Goroutine zu Schleife über eine Wiedergabeliste.Abbrechen eines context.Context mehr als einmal?

playlist := make([]*Media, 0) 
for _, path := range album.Paths { 
    media, err := NewMediaFromPath(path) 
    // return err 

    playlist = append(playlist, media) 
} 

for idx := range playlist { 
    player.SetMedia(playlist[idx]) 
    err = player.Play() 
    // check err 

    status, err := player.MediaState() 
    // check err 

    for status != MediaEnded && status != MediaStopped { 
     // update UI and check player status 
     // loop until the song finishes 
     status, err = player.MediaState() 
    } 
} 

Ich brauche einen Weg Cancelling dieses goroutine, wenn der Benutzer ein neues Album auswählt. Ich benutze context.Context, um dies zu tun (aber ich bin nicht überzeugt, dass es die beste Lösung ist).

Ich schaffe das ctx

ctx, cancel := context.WithCancel(context.Background()) 

So im UI-Event-Handler, die play()func die goroutine cancel().

Dies funktioniert, wenn ich in der Update UI überprüfen for Schleife:

 select { 
     case <-ctx.Done(): 
      return err 
     default: 
      time.Sleep(50 * time.Millisecond) 
     } 

Dann wird der Kanal ctx.Done() geschlossen ist und die nächsten Alben gespielt wird immer statt Schleife zurück.

Gibt es eine Möglichkeit, eine context.Context zu annullieren?

Wenn nicht, gibt es eine bessere Möglichkeit, diese Goroutine (und die folgenden Goroutines) abzubrechen?

Alternativ habe ich versucht, waitgroups zu verwenden,

go func() { 
     wg.Wait() 
     wg.Add(1) 
     err = playAlbum(
      done, 
      player, 
      *albums[s], 
      list, 
      status, 
     ) 
     wg.Done() 
     // handle err 
    }() 

Aber dann bekomme ich eine Panik

Antwort

1

Was ist ein Kanal mit dem goroutine abbrechen?

select { 
case <-chClose: 
    return 
default: 
} 

Ihre cancel() Anruf einfach den Kanal schließen konnte:

close(chClose) 

aber dann kann man es nicht wieder schließen! Du musst also sicherstellen, dass dein neues Album einen neuen chClose hat. Abhängig von Ihrer Code-Struktur könnte dies die sauberere Lösung sein.

Alternativ können Sie nur einen Wert auf chClose senden einen Stopp der Go-Routine einzuleiten:

chClose <- 1 

Sie tun können, so oft wie Sie wollen.

Beachten Sie, dass, wenn es keine goroutine Zuhörens ist, wird dieser Block (oder, wenn Sie einen Puffer haben, werden Sie auf Schließen Routinen beenden, die noch nicht einmal gestartet haben -.> Sie brauchen eine saubere Architektur !!)