cómo detener un goroutine


Tengo un goroutine que llama a un método, y pasa el valor devuelto en un canal:

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

¿Cómo puedo detener tal goroutine?

Author: Kenny Grant, 2011-07-24

6 answers

EDITAR: Escribí esta respuesta apresuradamente, antes de darme cuenta de que tu pregunta es sobre enviar valores a un chan dentro de un goroutine. El enfoque a continuación se puede usar con un chan adicional como se sugirió anteriormente, o utilizando el hecho de que el chan que ya tiene es bidireccional, puede usar solo uno...

Si su goroutine existe únicamente para procesar los elementos que salen del chan, puede hacer uso del builtin" close " y el formulario de recepción especial para canal.

Es decir, una vez que haya terminado de enviar elementos en el chan, lo cierra. Luego, dentro de su goroutine, obtiene un parámetro adicional para el operador de recepción que muestra si el canal se ha cerrado.

Aquí hay un ejemplo completo (el waitgroup se usa para asegurarse de que el proceso continúe hasta que se complete 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()
}
 38
Author: laslowh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-05 14:13:06

Normalmente, se pasa el canal de señal goroutine a (posiblemente separado). Ese canal de señal se usa para introducir un valor cuando se desea que la goroutine se detenga. Las encuestas goroutine que canalizan regularmente. Tan pronto como detecta una señal, se cierra.

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

// Do stuff

// Quit goroutine
quit <- true
 89
Author: jimt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-24 15:39:24

No puedes matar a un goroutine desde fuera. Puedes indicar a un goroutine que deje de usar un canal, pero no hay ningún control sobre goroutines para hacer ningún tipo de gestión de meta. Las goroutinas están destinadas a resolver problemas de manera cooperativa, por lo que matar a alguien que se está portando mal casi nunca sería una respuesta adecuada. Si desea aislamiento por robustez, probablemente desee un proceso.

 25
Author: SteveMcQwark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-28 07:40:51

Sé que esta respuesta ya ha sido aceptada, pero pensé en lanzar mis 2cents. Me gusta usar el paquete tomb . Es básicamente un canal de salida suped up, pero hace cosas buenas como pasar de nuevo los errores también. La rutina bajo control todavía tiene la responsabilidad de verificar las señales de apagado remoto. Afaik no es posible obtener un " id " de un goroutine y matarlo si se está portando mal (es decir, atascado en un bucle infinito).

Aquí está un ejemplo simple que I probado:

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 salida debería ser como:

# Loop the loop
# Loop the loop
# Loop the loop
# Loop the loop
# Death from above
 8
Author: Kevin Cantwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-23 18:34:01

Personalmente, me gustaría usar range en un canal en una goroutine:

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

Dave ha escrito un gran post sobre esto: http://dave.cheney.net/2013/04/30/curious-channels .

 5
Author: mikespook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-14 06:22:15

Generalmente, puede crear un canal y recibir una señal de stop en la rutina go.

Hay dos formas de crear un canal en este ejemplo.

  1. Canal

  2. Context . En el ejemplo voy a hacer una demostración context.WithCancel

La primera demo, use 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 segunda demo, use 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")
}
 4
Author: zouying,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-16 00:43:51