質問

メソッドを呼び出すゴルチンがあり、チャネルで返された値を渡します。

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

そのようなゴルウチンを止めるにはどうすればよいですか?

役に立ちましたか?

解決

編集: 私はこの答えを急いで書きましたが、あなたの質問はゴロウチンの中のチャンに価値を送ることについてであることに気付きました。以下のアプローチは、上記の追加のチャンで使用するか、すでに持っているチャンが双方向であるという事実を使用して使用できます。

GoroutineがChanから出てくるアイテムを処理するためだけに存在する場合、チャンネルの「クローズ」ビルトインと特別な受信フォームを利用できます。

つまり、チャンにアイテムを送信し終わったら、それを閉じます。次に、ゴルチンの内部では、チャネルが閉じられているかどうかを示す受信オペレーターに追加のパラメーターを取得します。

完全な例を次に示します(Waitgroupは、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(おそらく個別の)信号チャネルを渡します。その信号チャネルは、ゴルウチンを停止させたいときに値を押し込むために使用されます。ゴルウチンは定期的にチャネリングします。信号が検出されるとすぐに、終了します。

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

// Do stuff

// Quit goroutine
quit <- true

外からゴルチンを殺すことはできません。ゴルチンを信号してチャンネルの使用を停止できますが、ゴルチンにはあらゆる種類のメタ管理を行うためのハンドルはありません。ゴルチンは問題を協力して解決することを目的としているため、不正行為をしている問題を殺すことは、決して適切な反応になることはありません。堅牢性のために隔離が必要な場合は、おそらくプロセスが必要です。

一般に、チャネルを作成し、ゴルウチンで停止信号を受信することができます。

この例でチャネルを作成する2つの方法があります。

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

2番目のデモ、使用 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セントを投げると思っていました。 パッケージ。それは基本的に、停止したQuitチャンネルですが、エラーもパスバックするような素晴らしいことをします。制御下のルーチンには、リモートキル信号をチェックする責任がまだあります。 Afaikゴルウチンの「ID」を取得して、それが不正行為をしている場合はそれを殺すことはできません(つまり、無限のループで立ち往生しています)。

これが私がテストした簡単な例です。

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