Вопрос

У меня есть горутина, которая вызывает метод и передает возвращаемое значение по каналу:

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

Как мне остановить такую ​​горутину?

Это было полезно?

Решение

РЕДАКТИРОВАТЬ: Я написал этот ответ в спешке, прежде чем понял, что ваш вопрос касается отправки значений чану внутри горутины.Описанный ниже подход можно использовать либо с дополнительным каналом, как предложено выше, либо, учитывая тот факт, что канал, который у вас уже есть, является двунаправленным, вы можете использовать только один...

Если ваша горутина существует исключительно для обработки элементов, поступающих из канала, вы можете использовать встроенную функцию «закрыть» и специальную форму приема для каналов.

То есть, как только вы закончите отправлять элементы на чан, вы закроете его.Затем внутри вашей горутины вы получаете дополнительный параметр для оператора приема, который показывает, закрыт ли канал.

Вот полный пример (группа ожидания используется, чтобы гарантировать, что процесс продолжается до завершения горутины):

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

Другие советы

Обычно вы передаете горутине (возможно, отдельный) сигнальный канал.Этот сигнальный канал используется для ввода значения, когда вы хотите, чтобы горутина остановилась.Горутинные опросы, которые регулярно передаются.Как только он обнаружит сигнал, он отключится.

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

// Do stuff

// Quit goroutine
quit <- true

Вы не можете убить горутину снаружи.Вы можете подать сигнал горутине о прекращении использования канала, но у горутин нет возможности выполнять какое-либо мета-управление.Горутины предназначены для совместного решения проблем, поэтому убийство того, кто ведет себя плохо, почти никогда не будет адекватным ответом.Если вам нужна изоляция для обеспечения надежности, вам, вероятно, понадобится процесс.

Как правило, вы можете создать канал и получить сигнал остановки в горутине.

В этом примере существует два способа создания канала.

  1. канал

  2. контекст.В примере я продемонстрирую 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 цента.мне нравится использовать могила упаковка.По сути, это улучшенный канал выхода, но он также делает хорошие вещи, например, возвращает любые ошибки.Подконтрольная процедура по-прежнему отвечает за проверку сигналов удаленного уничтожения.На самом деле невозможно получить «идентификатор» горутины и убить ее, если она ведет себя неправильно (т.е.:застрял в бесконечном цикле).

Вот простой пример, который я тестировал:

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top