Domanda

Ho un goroutine che chiama un metodo, e passa valore restituito su un canale:

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

Come si interrompe una simile goroutine?

È stato utile?

Soluzione

Modifica Ho scritto questa risposta in gran fretta, prima di rendersi conto che la tua domanda è circa l'invio di valori ad un chan all'interno di un goroutine. L'approccio seguito può essere utilizzato sia con un ulteriore chan come suggerito sopra, o sfruttando il fatto che la Chan si dispone già è bidirezionale, è possibile utilizzare solo quello ...

Se il goroutine esiste solamente per elaborare gli elementi in uscita dal chan, si può fare uso del "chiudere" incorporato e la speciale ricevono modulo per i canali.

Cioè, una volta che hai finito di inviare articoli sul chan, si chiude. Poi all'interno del vostro goroutine si ottiene un parametro in più per l'operatore che indica se il canale è stato chiuso ricezione.

Ecco un esempio completo (il waitgroup è usato per fare in modo che il processo continua fino al completamento 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()
}

Altri suggerimenti

In genere, si passa il goroutine un canale di segnale (forse a parte). Questo canale di segnale viene utilizzato per spingere un valore in cui si desidera che il goroutine di fermarsi. I sondaggi goroutine quel canale regolarmente. Non appena rileva un segnale, si chiude.

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

// Do stuff

// Quit goroutine
quit <- true

Non si può uccidere un goroutine dall'esterno. È possibile segnalare un goroutine di smettere di usare un canale, ma non c'è maniglia goroutines di fare qualsiasi tipo di meta-management. Goroutines sono destinati a risolvere i problemi in modo cooperativo, in modo da uccidere uno che è comportamento anomalo sarebbe quasi mai essere una risposta adeguata. Se si desidera che l'isolamento per la robustezza, probabilmente avrete bisogno di un processo.

In generale, si potrebbe creare un canale e di ricevere un segnale di arresto nella goroutine.

Ci due modi per creare il canale in questo esempio.

  1. canale

  2. contesto . Nell'esempio io demo context.WithCancel

Il primo demo, uso 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")
}

Il secondo demo, uso 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")
}

So che questa risposta è già stata accettata, ma ho pensato di buttare i miei 2Cents. Mi piace usare la pacchetto tomba . E 'fondamentalmente un suped up smettere di canale, ma fa le cose belle come passare di nuovo eventuali errori pure. La routine sotto controllo ha ancora la responsabilità di verificare per i segnali di uccidere a distanza. Per quanto ne so non è possibile ottenere un "id" di un goroutine e ucciderlo se è comportarsi male. (Es: bloccato in un ciclo infinito)

Ecco un semplice esempio che ho provato:

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)
}

L'output dovrebbe essere simile:

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

Personalmente, mi piacerebbe usare gamma su un canale in un goroutine:

https://play.golang.org/p/qt48vvDu8cd

Dave ha scritto un bel post su questo: http: // dave. cheney.net/2013/04/30/curious-channels .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top