Подтвердить что ты не робот

Как остановить горутин

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

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

Как остановить такой goroutine?

4b9b3361

Ответ 1

РЕДАКТИРОВАТЬ: Я написал этот ответ на скорую руку, прежде чем понять, что ваш вопрос о отправке значений Чан внутри 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()
}

Ответ 2

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

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

// Do stuff

// Quit goroutine
quit <- true

Ответ 3

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

Ответ 4

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

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

  1. канал

  2. контекст. В примере я 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")
}

Ответ 5

Я знаю, что этот ответ уже принят, но я думал, что брошу свои 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