2017-02-28 19 views
4

私は関数を呼び出すゴルーチンを持っています。特別なパラメータを指定して、このゴルーチンを開始または停止します。私の問題は、このコードが私のgoroutineを止めることはなく、毎回新しい仕事を生み出すことです。ゴルーチンを止める方法

quit := make(chan bool) 
run := make(chan bool) 

    go func() { 
     for { 
      select { 
      case <-quit: 
       close(run) 
      case <-run: 
       myFunc(c) 
      default: 
      } 
     } 
    }() 

    if x == true { 
     quit <- true 
    } else { 
     run <- true 
    } 

ルーチンを停止するにはどうすればよいですか?

+1

これに対してブール値を使用している場合、なぜ2つのチャネルを作成していますか? – Gant

答えて

1

runチャネルを閉じると、case <-runが常にトリガします。閉チャネルでリスニングすると、すぐにゼロ値が返されます。

ゴルーチンを停止したい場合は、<-quitシグナルを受信した後に戻る必要があります。サイドノートとして

、あなたのdefault:句は、forループを積極的に(あなたはまだ両方のチャンネル上で待機します)あなたはそれを取り除く必要があり、作業になり

1

ここでどのようなシグナリングの孤立コメントrunableバージョンですシステムが実装される可能性があります。

package main 

import (
    "time" 
    "log" 
) 

func main() { 
    statusChannel := make(chan bool) 
    go applicationLoop(statusChannel) 

    // reasonably random outcome for testing 
    if time.Now().Unix() % 2 == 0 { 
     statusChannel<-true 
    } else { 
     statusChannel<-false 
    } 

    for { 
     // busy loop for testing 
     time.Sleep(1000) 
    } 
} 

func applicationLoop(statusChannel chan bool) { 
    defer close(statusChannel) 
    for { 
     log.Printf("waiting for signal...\n") 
     shouldContinue := <-statusChannel 
     if !shouldContinue { 
      log.Print("received false, breaking...\n") 
      break 
     } 
     // run your code here 
     // you should use a second channel to return results, as the channel is not buffered 
     log.Print("working...\n") 
    } 
} 

statusChannel中に値を送信することの例では、あなたの顔に爆破ようになります値のために待機していないことに注意してください。ゴルーチンが信号を聞くために戻ったときに、バッファされたチャンネルまたは mainに戻ってくるチャンネルを使用してください。

+0

それだけです!走って、ありがとう! –

+0

チャネルから読み込みを行い、値をチェックする理由はありません。 if文でチャンネルから直接読むことができます: 'if!< - statusChannel {'。例:https://play.golang.org/p/3q5jpC19rW。現在使用しているブール式の結果を無条件にifステートメントの条件として送信するだけで、ステータスチャネルでセンドを圧縮することもできます。 – Kaedys

1

この問題には2つの部分があります。

最初に、親ゴルーチンが停止しても、子どものすべてが通知を受けて停止するように、何らかの方法で停止させる必要があります。

一方、親は、完了するまで子どもを待つ必要があります。さもなければ、いくつかのgoroutinesが正しく終了する前に、goroutineから戻ったり、アプリケーションから終了したりするでしょう。

わかりやすくするために、エラー処理、タイムアウトなどの実装は無視しています。

context.Contextを使用すると、実行コンテキスト処理ツールの優れた階層が得られ、2番目の問題を解決するために、sync.WaitGroupを使用すると、ゴルーチンのグループがタスクを完了するのを待つことができます。簡単なデモは、次のようになります。

[ info ] level2 
[ info ] level2 
[ info ] level2 
[ info ] level1 
[ info ] level2 
[ info ] level1 
[ info ] level2 
[ info ] level2 

現在context.Contextsync.WaitGroupを組み合わせた機能を提供する公式パッケージはありません。のようないくつかの出力が私たちに与え

func main() { 
    all := &sync.WaitGroup{} 
    rootCtx, rootCancel := context.WithCancel(context.Background()) 

    all.Add(1) 
    go level1(rootCtx, all) 

    // just to simulate stop, we could use an os signal instead 
    // app ends after 3 seconds 
    go func() { 
     time.Sleep(time.Second * 3) 
     rootCancel() 
    }() 

    all.Wait() 
} 

func level1(parent context.Context, all *sync.WaitGroup) { 
    defer all.Done() 
    l1Ctx, l1Cancel := context.WithCancel(parent) 
    defer l1Cancel() 

    for i := 0; i < 3; i++ { 
     all.Add(1) 
     go level2(l1Ctx, all) 
    } 

    for { 
     select { 
     case <-parent.Done(): 
      return 
     // other cases if any, 
     // this is a sample 
     case <-time.After(time.Second): 
      log.Println(`level1`) 
     } 
    } 
} 

func level2(parent context.Context, all *sync.WaitGroup) { 
    defer all.Done() 
    for { 
     select { 
     case <-parent.Done(): 
      return 
     case <-time.After(time.Second): 
      log.Println(`level2`) 
     } 
    } 
} 

。一番近いのはerrgroupで、この機能に似ています。

関連する問題