web-dev-qa-db-ja.com

タイムアウト時にゴルーチンの実行を停止する

タイムアウト時にゴルーチンの実行を停止したい。しかし、それは私にとってはうまくいかないようです。 irisフレームワークを使用しています。

  type Response struct {
    data   interface{}
    status bool
  }

  func (s *CicService) Find() (interface{}, bool) {

    ch := make(chan Response, 1)

    go func() {
      time.Sleep(10 * time.Second)

      fmt.Println("test")
      fmt.Println("test1")

      ch <- Response{data: "data", status: true}
    }()

    select {
    case <-ch:
      fmt.Println("Read from ch")
      res := <-ch
      return res.data, res.status
    case <-time.After(50 * time.Millisecond):
      return "Timed out", false
    }

  }

出力:

 Timed out
 test
 test1

期待される出力:

 Timed out

誰かがここに欠けているものを指摘できますか?タイムアウトしますが、それでもgoroutineを実行してtesttest1を出力します。タイムアウトが発生したらすぐにゴルーチンの実行を停止したいだけです。

6

実行の途中でゴルーチンの実行を「中断」する良い方法はありません。

Goは、並行性のフォーク結合モデルを使用します。つまり、新しいゴルーチンを「フォーク」して作成し、「結合ポイント」に到達するまで、そのゴルーチンのスケジュール方法を制御できません。ジョインポイントは、複数のゴルーチン間のある種の同期です。例えばチャネルで値を送信します。

あなたの特定の例をとると、この行:

ch <- Response{data: "data", status: true}

...バッファリングされたチャネルであるため、値を送信できます。ただし、作成したタイムアウトは次のとおりです。

case <-time.After(50 * time.Millisecond):
  return "Timed out", false

これらのタイムアウトは、チャネルの「受信者」または「リーダー」で発生し、not「送信者」で発生します。この回答の冒頭で述べたように、いくつかの同期技術を使用せずにゴルーチンの実行を中断する方法はありません。

タイムアウトはチャネルからのゴルーチンの「読み取り」であるため、チャネルで送信するゴルーチンの実行を停止するものは何もありません。

9
Zak

goroutine処理を制御する最良の方法は context (std goライブラリ)です。

ゴルーチン内の何かをキャンセルして実行を停止することができますゴルーチンリークの可能性なし

ここでは単純です あなたのケースのタイムアウトによるキャンセル。

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ch := make(chan Response, 1)

go func() {
    time.Sleep(1 * time.Second)

    select {
    default:
        ch <- Response{data: "data", status: true}
    case <-ctx.Done():
        fmt.Println("Canceled by timeout")
        return
    }
}()

select {
case <-ch:
    fmt.Println("Read from ch")
case <-time.After(500 * time.Millisecond):
    fmt.Println("Timed out")
}
4
Oleksandr Mosur

あなたはグルメリークを持っています、あなたはこのようにタイムアウトする前にゴルーチンを返すためにいくつかの完了したアクションを処理しなければなりません:

func (s *CicService) Find() (interface{}, bool) {

    ch := make(chan Response, 1)
    done := make(chan struct{})
    go func() {
        select {
        case <-time.After(10 * time.Second):
        case <-done:
            return
        }
        fmt.Println("test")
        fmt.Println("test1")
        ch <- Response{data: "data", status: true}
    }()
    select {
    case res := <-ch:
        return res.data, res.status
    case <-time.After(50 * time.Millisecond):
        done <- struct{}{}
        return "Timed out", false
    }

}
0
Hau Ma