как остановить goroutine
У меня есть goroutine, который вызывает метод и передает возвращаемое значение по каналу:
ch := make(chan int, 100)
go func(){
for {
ch <- do_stuff()
}
}()
Как мне остановить такой goroutine?
6 ответов:
EDIT:Я написал этот ответ в спешке, прежде чем понял, что ваш вопрос заключается в отправке значений chan внутри goroutine. Подход ниже может быть использован либо с дополнительным Чан, как предложено выше, или с использованием того факта, что Чан У вас уже двунаправленный, вы можете использовать только один...
Если ваш goroutine существует исключительно для обработки элементов, выходящих из chan, вы можете использовать встроенный "close" и специальная форма приема для каналов.
то есть, как только вы закончите отправлять элементы на chan, вы его закроете. Затем внутри вашего goroutine вы получаете дополнительный параметр для оператора приема, который показывает, был ли канал закрыт.
вот полный пример (группа ожидания используется, чтобы убедиться, что процесс продолжается до завершения 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() }
Как правило, вы передаете goroutine a (возможно, отдельный) сигнальный канал. Этот сигнальный канал используется для ввода значения, когда вы хотите, чтобы goroutine остановился. Опросы горутина, которые регулярно канал. Как только он обнаруживает сигнал, он уходит.
quit := make(chan bool) go func() { for { select { case <- quit: return default: // Do other stuff } } }() // Do stuff // Quit goroutine quit <- true
ты не можешь убить горутина извне. Вы можете сигнализировать goroutine прекратить использование канала, но на goroutines нет дескриптора для какого-либо мета-управления. Goroutines предназначены для совместного решения проблем, поэтому убийство того, кто плохо себя ведет, почти никогда не будет адекватным ответом. Если вы хотите изоляции для надежности, вы, вероятно, хотите процесс.
Я знаю, что этот ответ уже принят, но я думал, что брошу свои 2cents. Мне нравится использовать гроб пакета. Это в основном suped up quit channel, но он делает хорошие вещи, такие как передача любых ошибок. Рутина под контролем по-прежнему несет ответственность за проверку сигналов дистанционного уничтожения. Afaik невозможно получить "идентификатор" goroutine и убить его, если он плохо себя ведет (т. е. застрял в бесконечном цикле).
вот простой пример, который Я проверил:
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) }
результат должен выглядеть так:
# Loop the loop # Loop the loop # Loop the loop # Loop the loop # Death from above
лично я хотел бы использовать диапазон на канале в goroutine:
http://play.golang.org/p/KjG8FLzPoz
Дэйв написал отличный пост об этом:http://dave.cheney.net/2013/04/30/curious-channels.
как правило, вы можете создать канал и получить стоп-сигнал в подпрограмме go.
есть два способа создать канал в этом примере.
канал
контекст. В примере я буду демо
context.WithCancel
первая демонстрация, используйте
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") }
вторая демонстрация, используйте
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") }