Frage

Ich habe eine Goroutine, die eine Methode aufruft, und übergibt den zurückgegebenen Wert auf einem Kanal:

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

Wie stoppe ich so eine Goroutine?

War es hilfreich?

Lösung

BEARBEITEN: Ich habe diese Antwort in Eile geschrieben, bevor ich feststellte, dass es in Ihrer Frage darum geht, Werte an einen Chan in einer Goroutine zu senden. Der folgende Ansatz kann entweder mit einem zusätzlichen Chan verwendet werden, wie oben vorgeschlagen, oder mit der Tatsache, dass der Chan, den Sie bereits haben, bidirektional ist, können Sie nur den ... verwenden ...

Wenn Ihre Goroutine ausschließlich vorhanden ist, um die aus dem Chan stehenden Gegenstände zu verarbeiten, können Sie das "enge" gebaute und das spezielle Empfangsformular für Kanäle verwenden.

Das heißt, sobald Sie mit dem Versenden von Gegenständen auf dem Chan fertig sind, schließen Sie es. In Ihrer Goroutine erhalten Sie dann einen zusätzlichen Parameter für den Empfangsbetreiber, der zeigt, ob der Kanal geschlossen wurde.

Hier ist ein komplettes Beispiel (die Karteigruppe wird verwendet, um sicherzustellen, dass der Vorgang fortgesetzt wird, bis die Goroutine abgeschlossen ist):

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

Andere Tipps

Normalerweise passieren Sie den Signalkanal von Goroutine A (möglicherweise separat). Dieser Signalkanal wird verwendet, um einen Wert in den Stopp der Goroutine zu drücken. Die Goroutine befragt, die regelmäßig kanalisieren. Sobald es ein Signal erkennt, beendet es.

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

// Do stuff

// Quit goroutine
quit <- true

Sie können keine Goroutine von außen töten. Sie können eine Goroutine signalisieren, dass sie die Verwendung eines Kanals nicht mehr verwenden, aber es gibt keinen Griff für Goroutines, um irgendeine Art von Meta -Management durchzuführen. Goroutinen sollen kooperativ Probleme lösen, sodass das Töten eines, das sich schlecht benimmt, fast nie eine angemessene Reaktion wäre. Wenn Sie Isolation für Robustheit wünschen, möchten Sie wahrscheinlich einen Prozess.

Im Allgemeinen können Sie einen Kanal erstellen und ein Stoppsignal in der Goroutine erhalten.

In diesem Beispiel zwei Möglichkeiten, Kanal zu erstellen.

  1. Kanal

  2. Kontext. In dem Beispiel werde ich Demo context.WithCancel

Die erste Demo, verwenden Sie 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")
}

Die zweite Demo, verwenden Sie 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")
}

Ich weiß Grab Paket. Es ist im Grunde genommen ein Verkleinerungskanal, aber es tut auch schöne Dinge wie Fehler zurück. Die Routine unter Kontrolle hat immer noch die Verantwortung für die Überprüfung nach Fernkill -Signalen. AFAIK Es ist nicht möglich, eine "Ausweise" einer Goroutine zu bekommen und sie zu töten, wenn es schlecht sich verhalten (dh in einer unendlichen Schleife stecken).

Hier ist ein einfaches Beispiel, das ich getestet habe:

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

Die Ausgabe sollte aussehen wie:

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

Persönlich möchte ich Range auf einem Kanal in einer Goroutine verwenden:

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

Dave hat einen tollen Beitrag darüber geschrieben: http://dave.cheney.net/2013/04/30/curious-channels.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top