У меня есть goroutine, который вызывает метод и передает возвращаемое значение по каналу:
ch := make(chan int, 100)
go func(){
for {
ch <- do_stuff()
}
}()
Как остановить такой goroutine?
У меня есть goroutine, который вызывает метод и передает возвращаемое значение по каналу:
ch := make(chan int, 100)
go func(){
for {
ch <- do_stuff()
}
}()
Как остановить такой 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, чтобы делать любое управление мета. Горотины предназначены для совместного решения проблем, поэтому убийство человека, которое плохо ведет себя, почти никогда не будет адекватным ответом. Если вам нужна изоляция для надежности, вы, вероятно, хотите выполнить процесс.
Как правило, вы можете создать канал и получить сигнал остановки в программе.
В этом примере есть два способа создания канала.
канал
контекст. В примере я context.WithCancel
демонстрационный 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")
}
Я знаю, что этот ответ уже принят, но я думал, что брошу свои 2центы. Мне нравится использовать гробница. Это в основном поддерживаемый канал выхода, но он делает приятные вещи, например, возвращать любые ошибки. Под контролем под контролем все еще лежит проверка на наличие удаленных сигналов. Afaik невозможно получить "id" из 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
Лично я хотел бы использовать диапазон на канале в программе:
https://play.golang.org/p/qt48vvDu8cd
Дэйв написал отличный пост об этом: http://dave.cheney.net/2013/04/30/curious-channels.