Une autre réponse, en fonction de votre situation, est d'utiliser un Go Context. Je n'ai ni le temps ni les connaissances nécessaires pour créer une réponse à ce sujet. Je voulais juste le mentionner ici pour que les personnes qui recherchent et trouvent cette réponse insatisfaisante aient un autre fil à tirer (jeu de mots). Dans la plupart des cas, vous devez faire ce que suggère la réponse acceptée. Cette réponse mentionne les contextes: stackoverflow.com/a/47302930/167958
Omnifarious
Réponses:
51
EDIT: J'ai écrit cette réponse à la hâte, avant de réaliser que votre question porte sur l'envoi de valeurs à un chan dans un goroutine. L'approche ci-dessous peut être utilisée soit avec un chan supplémentaire comme suggéré ci-dessus, soit en utilisant le fait que le chan que vous avez déjà est bidirectionnel, vous pouvez utiliser juste celui ...
Si votre goroutine existe uniquement pour traiter les éléments sortant du chan, vous pouvez utiliser la fonction intégrée "close" et le formulaire de réception spécial pour les chaînes.
Autrement dit, une fois que vous avez terminé d'envoyer des éléments sur le chan, vous le fermez. Ensuite, à l'intérieur de votre goroutine, vous obtenez un paramètre supplémentaire pour l'opérateur de réception qui indique si le canal a été fermé.
Voici un exemple complet (le waitgroup est utilisé pour s'assurer que le processus continue jusqu'à ce que la goroutine se termine):
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()}
Le corps de la goroutine interne est écrit de manière plus idiomatique en utilisant deferto call wg.Done(), et une range chboucle pour itérer sur toutes les valeurs jusqu'à ce que le canal soit fermé.
Alan Donovan
115
En règle générale, vous passez la goroutine par un canal de signal (éventuellement séparé). Ce canal de signal est utilisé pour insérer une valeur lorsque vous souhaitez que le goroutine s'arrête. Les sondages goroutine qui canalisent régulièrement. Dès qu'il détecte un signal, il se ferme.
quit := make(chan bool)
go func(){for{select{case<- quit:returndefault:// Do other stuff}}}()// Do stuff// Quit goroutine
quit <-true
Pas assez bon. Et si le goroutine est coincé dans une boucle sans fin, à cause d'un bug?
Elazar Leibovich le
232
Ensuite, le bogue devrait être corrigé.
jimt
13
Elazar, ce que vous suggérez est un moyen d'arrêter une fonction après l'avoir appelée. Un goroutine n'est pas un fil. Il peut s'exécuter dans un thread différent ou dans le même thread que le vôtre. Je ne connais aucun langage qui prend en charge ce que vous pensez que Go devrait prendre en charge.
Jeremy Wall
5
@jeremy Pas en désaccord pour Go, mais Erlang vous permet de tuer un processus qui exécute une fonction de bouclage.
MatthewToday
10
Le multitâche est coopératif et non préventif. Un goroutine dans une boucle n'entre jamais dans le planificateur, donc il ne peut jamais être tué.
Jeff Allen
34
Vous ne pouvez pas tuer un goroutine de l'extérieur. Vous pouvez signaler à un goroutine d'arrêter d'utiliser un canal, mais il n'y a pas de poignée sur les goroutines pour faire une sorte de méta-gestion. Les goroutines sont destinées à résoudre les problèmes de manière coopérative, donc tuer celui qui se comporte mal ne serait presque jamais une réponse adéquate. Si vous voulez une isolation pour la robustesse, vous voulez probablement un processus.
Et vous voudrez peut-être examiner le paquet encoding / gob, qui permettrait à deux programmes Go d'échanger facilement des structures de données via un tube.
Jeff Allen
Dans mon cas, j'ai un goroutine qui sera bloqué sur un appel système, et je dois lui dire d'abandonner l'appel système puis de quitter. Si j'étais bloqué sur une chaîne lue, il serait possible de faire ce que vous suggérez.
Omnifarious
J'ai déjà vu ce problème. La façon dont nous l'avons "résolu" était d'augmenter le nombre de threads au démarrage de l'application pour correspondre au nombre de goroutines qui pourraient éventuellement + le nombre de CPU
rouzier
20
Généralement, vous pouvez créer un canal et recevoir un signal d'arrêt dans le goroutine.
Il existe deux façons de créer un canal dans cet exemple.
canal
contexte . Dans l'exemple, je vais faire une démonstrationcontext.WithCancel
La première démo, utilisez channel:
package main
import"fmt"import"time"
func do_stuff()int{return1}
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, utilisez 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{}{}returndefault:
fmt.Println("for loop")}
time.Sleep(500* time.Millisecond)}}(ctx)
go func(){
time.Sleep(3* time.Second)
cancel()}()<-forever
fmt.Println("finish")}
Je sais que cette réponse a déjà été acceptée, mais j'ai pensé jeter mes 2cents dedans. J'aime utiliser le paquet tomb . C'est fondamentalement un canal d'arrêt remplacé, mais il fait également de bonnes choses comme renvoyer les erreurs. La routine sous contrôle a toujours la responsabilité de vérifier les signaux d'arrêt à distance. Afaik il n'est pas possible d'obtenir un "identifiant" d'un goroutine et de le tuer s'il se comporte mal (ie: coincé dans une boucle infinie).
Voici un exemple simple que j'ai testé:
package main
import("launchpad.net/tomb""time""fmt")
type Procstruct{Tomb tomb.Tomb}
func (proc *Proc)Exec(){
defer proc.Tomb.Done()// Must call only oncefor{select{case<-proc.Tomb.Dying():returndefault:
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
Ce package est assez intéressant! Avez-vous testé pour voir ce que tombfait la goroutine au cas où quelque chose se passerait à l'intérieur et semerait la panique, par exemple? Techniquement parlant, le goroutine sort dans ce cas, donc je suppose qu'il appellera toujours le différé proc.Tomb.Done()...
Gwyneth Llewelyn
1
Salut Gwyneth, oui proc.Tomb.Done()serait exécuté avant que la panique plante le programme, mais à quelle fin? Il est possible que le goroutine principal ait une très petite fenêtre d'opportunité pour exécuter certaines instructions, mais il n'a aucun moyen de se remettre d'une panique dans un autre goroutine, donc le programme plante toujours. Les documents disent: "Lorsque la fonction F appelle panique, l'exécution de F s'arrête, toutes les fonctions différées de F sont exécutées normalement, puis F retourne à son appelant .. Le processus continue dans la pile jusqu'à ce que toutes les fonctions de la goroutine actuelle soient retournées, à quel moment le programme se bloque. "
Kevin Cantwell
7
Personnellement, j'aimerais utiliser range sur un canal dans un goroutine:
Réponses:
EDIT: J'ai écrit cette réponse à la hâte, avant de réaliser que votre question porte sur l'envoi de valeurs à un chan dans un goroutine. L'approche ci-dessous peut être utilisée soit avec un chan supplémentaire comme suggéré ci-dessus, soit en utilisant le fait que le chan que vous avez déjà est bidirectionnel, vous pouvez utiliser juste celui ...
Si votre goroutine existe uniquement pour traiter les éléments sortant du chan, vous pouvez utiliser la fonction intégrée "close" et le formulaire de réception spécial pour les chaînes.
Autrement dit, une fois que vous avez terminé d'envoyer des éléments sur le chan, vous le fermez. Ensuite, à l'intérieur de votre goroutine, vous obtenez un paramètre supplémentaire pour l'opérateur de réception qui indique si le canal a été fermé.
Voici un exemple complet (le waitgroup est utilisé pour s'assurer que le processus continue jusqu'à ce que la goroutine se termine):
la source
defer
to callwg.Done()
, et unerange ch
boucle pour itérer sur toutes les valeurs jusqu'à ce que le canal soit fermé.En règle générale, vous passez la goroutine par un canal de signal (éventuellement séparé). Ce canal de signal est utilisé pour insérer une valeur lorsque vous souhaitez que le goroutine s'arrête. Les sondages goroutine qui canalisent régulièrement. Dès qu'il détecte un signal, il se ferme.
la source
Vous ne pouvez pas tuer un goroutine de l'extérieur. Vous pouvez signaler à un goroutine d'arrêter d'utiliser un canal, mais il n'y a pas de poignée sur les goroutines pour faire une sorte de méta-gestion. Les goroutines sont destinées à résoudre les problèmes de manière coopérative, donc tuer celui qui se comporte mal ne serait presque jamais une réponse adéquate. Si vous voulez une isolation pour la robustesse, vous voulez probablement un processus.
la source
Généralement, vous pouvez créer un canal et recevoir un signal d'arrêt dans le goroutine.
Il existe deux façons de créer un canal dans cet exemple.
canal
contexte . Dans l'exemple, je vais faire une démonstration
context.WithCancel
La première démo, utilisez
channel
:La deuxième démo, utilisez
context
:la source
Je sais que cette réponse a déjà été acceptée, mais j'ai pensé jeter mes 2cents dedans. J'aime utiliser le paquet tomb . C'est fondamentalement un canal d'arrêt remplacé, mais il fait également de bonnes choses comme renvoyer les erreurs. La routine sous contrôle a toujours la responsabilité de vérifier les signaux d'arrêt à distance. Afaik il n'est pas possible d'obtenir un "identifiant" d'un goroutine et de le tuer s'il se comporte mal (ie: coincé dans une boucle infinie).
Voici un exemple simple que j'ai testé:
La sortie devrait ressembler à:
la source
tomb
fait la goroutine au cas où quelque chose se passerait à l'intérieur et semerait la panique, par exemple? Techniquement parlant, le goroutine sort dans ce cas, donc je suppose qu'il appellera toujours le différéproc.Tomb.Done()
...proc.Tomb.Done()
serait exécuté avant que la panique plante le programme, mais à quelle fin? Il est possible que le goroutine principal ait une très petite fenêtre d'opportunité pour exécuter certaines instructions, mais il n'a aucun moyen de se remettre d'une panique dans un autre goroutine, donc le programme plante toujours. Les documents disent: "Lorsque la fonction F appelle panique, l'exécution de F s'arrête, toutes les fonctions différées de F sont exécutées normalement, puis F retourne à son appelant .. Le processus continue dans la pile jusqu'à ce que toutes les fonctions de la goroutine actuelle soient retournées, à quel moment le programme se bloque. "Personnellement, j'aimerais utiliser range sur un canal dans un goroutine:
https://play.golang.org/p/qt48vvDu8cd
Dave a écrit un excellent article à ce sujet: http://dave.cheney.net/2013/04/30/curious-channels .
la source