comment arrêter une goroutine

J’ai un goroutine qui appelle une méthode et transmet la valeur renvoyée sur un canal:

ch := make(chan int, 100) go func(){ for { ch <- do_stuff() } }() 

Comment puis-je arrêter une telle goroutine?

EDIT: J’ai écrit cette réponse à la hâte, avant de réaliser que votre question concerne l’envoi de valeurs à un chan dans une goroutine. L’approche ci-dessous peut être utilisée avec un chan supplémentaire comme suggéré ci-dessus, ou en utilisant le fait que le chan que vous avez déjà est bidirectionnel, vous pouvez utiliser juste celui-là …

Si votre firebase database existe uniquement pour traiter les éléments provenant du canal, vous pouvez utiliser le répertoire “close” et le formulaire de réception spécial pour les canaux.

C’est-à-dire qu’une fois que vous avez fini d’envoyer des éléments sur le chan, vous le fermez. Ensuite, à l’intérieur de votre firebase database, vous obtenez un paramètre supplémentaire à l’opérateur de réception qui indique si le canal a été fermé.

Voici un exemple complet (le groupe d’attente est utilisé pour s’assurer que le processus se poursuit jusqu’à la fin de la goroutine):

 package main import "sync" func main() { var wg sync.WaitGroup wg.Add(1) ch := make(chan int) go func() { for { foo, ok := <- ch if !ok { println("done") wg.Done() return } println(foo) } }() ch <- 1 ch <- 2 ch <- 3 close(ch) wg.Wait() } 

En règle générale, vous passez la goroutine à un canal de signal (éventuellement séparé). Ce canal de signal est utilisé pour pousser une valeur lorsque vous voulez que le goroutine s’arrête. Le goroutine interroge régulièrement ce canal. Dès qu’il détecte un signal, il se ferme.

 quit := make(chan bool) go func() { for { select { case <- quit: return default: // Do other stuff } } }() // Do stuff // Quit goroutine quit <- true 

Vous ne pouvez pas tuer une goroutine de l’extérieur. Vous pouvez signaler à une goroutine d’arrêter d’utiliser un canal, mais les goroutines ne peuvent pas gérer les méta-méthodes. Les goroutines sont destinées à résoudre les problèmes de manière coopérative. Tuer une personne qui se comporte mal ne serait presque jamais une réponse adéquate. Si vous souhaitez isoler pour plus de robustesse, vous souhaitez probablement un processus.

Je sais que cette réponse a déjà été acceptée, mais je pensais que je jetterais mes 2 cents. J’aime utiliser le paquet de tombes . Il s’agit essentiellement d’un canal de sortie supprimé, mais il fait de belles choses, comme le fait de renvoyer toutes les erreurs. La routine sous contrôle a toujours la responsabilité de vérifier les signaux de mise à mort à distance. Il n’est pas possible d’obtenir un “identifiant” de goroutine et de le tuer s’il se comporte mal (c’est-à-dire coincé dans une boucle infinie).

Voici un exemple simple que j’ai testé:

 package main import ( "launchpad.net/tomb" "time" "fmt" ) type Proc struct { Tomb tomb.Tomb } func (proc *Proc) Exec() { defer proc.Tomb.Done() // Must call only once for { select { case <-proc.Tomb.Dying(): return default: time.Sleep(300 * time.Millisecond) fmt.Println("Loop the loop") } } } func main() { proc := &Proc{} go proc.Exec() time.Sleep(1 * time.Second) proc.Tomb.Kill(fmt.Errorf("Death from above")) err := proc.Tomb.Wait() // Will return the error that killed the proc fmt.Println(err) } 

La sortie devrait ressembler à:

 # Loop the loop # Loop the loop # Loop the loop # Loop the loop # Death from above 

Personnellement, je voudrais utiliser la scope sur un canal dans une goroutine:

http://play.golang.org/p/KjG8FLzPoz

Dave a écrit un excellent article à ce sujet: http://dave.cheney.net/2013/04/30/curious-channels .

Généralement, vous pouvez créer un canal et recevoir un signal d’arrêt dans la routine go.

Il existe deux façons de créer un canal dans cet exemple.

  1. canal

  2. contexte Dans l’exemple, je vais faire une démonstration du context.WithCancel

La première démo, utilisez le channel :

 package main import "fmt" import "time" func do_stuff() int { return 1 } func main() { ch := make(chan int, 100) done := make(chan struct{}) go func() { for { select { case ch <- do_stuff(): case <-done: close(ch) return } time.Sleep(100 * time.Millisecond) } }() go func() { time.Sleep(3 * time.Second) done <- struct{}{} }() for i := range ch { fmt.Println("receive value: ", i) } fmt.Println("finish") } 

La deuxième démo, utilise le context :

 package main import ( "context" "fmt" "time" ) func main() { forever := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) go func(ctx context.Context) { for { select { case <-ctx.Done(): // if cancel() execute forever <- struct{}{} return default: fmt.Println("for loop") } time.Sleep(500 * time.Millisecond) } }(ctx) go func() { time.Sleep(3 * time.Second) cancel() }() <-forever fmt.Println("finish") }