2017-12-19 7 views
0

私は、無限の数の値を生成できるゴルーチンを持っていますが、それぞれの値を見つけるまでに時間がかかります。私は時間制限を追加する方法、例えば10秒後に、私の関数が今までに受け取った最良の値で何かをする方法を見つけようとしています。特定の時間量のゴルーチンからの値の受け取り

これは、チャネル、タイマーを使用して、私の現在の「解決策」である:

// the goroutine which runs infinitely 
// (or at least a very long time for high values of depth) 
func runSearch(depth int, ch chan int) { 
    for i := 1; i <= depth; i++ { 
     fmt.Printf("Searching to depth %v\n", i) 
     ch <- search(i) 
    } 
} 

// consumes progressively better values until the channel is closed 
func awaitBestResult(ch chan int) { 
    var result int 
    for result := range ch { 
     best = result 
    } 

    // do something with best result here 
} 

// run both consumer and producer 
func main() { 
    timer := time.NewTimer(time.Millisecond * 2000) 

    ch := make(chan int) 

    go runSearch(1000, ch) 
    go awaitBestResult(ch) 

    <-timer.C 
    close(ch) 
} 

は、これは主に動作します - タイマー終了後に最良の結果が処理され、チャネルが閉じられています。しかし、チャンネルがメイン関数によって閉じられているので、私はrunSearchゴルーチンからパニック(panic: send on closed channel)を取得します。

タイマー完了後、最初のゴルーチンの実行を停止するにはどうすればよいですか?どんな助けもありがとうございます。

+1

main()で次に

func runSearch(ctx context.Context, depth int, ch chan int) { for i := 1; i <= depth; i++ { select { case <- ctx.Done() // Context cancelled, return return default: } fmt.Printf("Searching to depth %v\n", i) ch <- search(i) } } 

'メイン'。 goroutineの外側でそれを行う必要がある場合は、goroutineがチェックする別のチャネルを作成して、それを閉じて 'main'でgoroutineに停止するように指示することができます。 –

答えて

0

ゴルーチンは、処理が完了した時点を把握して、クローズドチャネルに書き込みを試みたりパニックに陥らないようにする必要があります。

これはcontextパッケージにぴったりのケースのように聞こえる:それは中にいることをやってするのではなく、時間を使い果たした後、あなたは、それ自体が停止ゴルーチンを持つことができ

// run both consumer and producer 
func main() { 
    ctx := context.WithTimeout(context.Background, 2 * time.Second) 

    ch := make(chan int) 

    go runSearch(ctx, 1000, ch) 
    go awaitBestResult(ch) 

    close(ch) 
} 
0

あなたの送信ゴルーチンrunSearchが明らかにタイマーより長く、あなたのmainゴルーチンによって既に閉じられているチャンネルの値を送信しようとしているので、パニックになっています。タイマーが終了してメインのチャンネルを閉じる前に、値を送信しないように送信ゴールーを通知する方法を考案する必要があります。一方、あなたの検索がより早く終了する場合は、移動するにはmainに連絡する必要があります。 1つのチャネルを使用して、競合条件が存在しないように同期することができます。最後に、コンシューマがいつメインを終了する前にすべてのデータを処理したかを知る必要があります。

ここに役立つ情報があります。

package main 

import (
    "fmt" 
    "sync" 
    "time" 
) 

var mu sync.Mutex //To protect the stopped variable which will decide if a value is to be sent on the signalling channel 
var stopped bool 

func search(i int) int { 
    time.Sleep(1 * time.Millisecond) 
    return (i + 1) 
} 

// (or at least a very long time for high values of depth) 
func runSearch(depth int, ch chan int, stopSearch chan bool) { 

    for i := 1; i <= depth; i++ { 
     fmt.Printf("Searching to depth %v\n", i) 
     n := search(i) 
     select { 
     case <-stopSearch: 
      fmt.Println("Timer over! Searched till ", i) 
      return 
     default: 
     } 

     ch <- n 
     fmt.Printf("Sent depth %v result for processing\n", i) 
    } 

    mu.Lock() //To avoid race condition with timer also being 
    //completed at the same time as execution of this code 
    if stopped == false { 
     stopped = true 
     stopSearch <- true 
     fmt.Println("Search completed") 
    } 
    mu.Unlock() 

} 

// consumes progressively better values until the channel is closed 
func awaitBestResult(ch chan int, doneProcessing chan bool) { 
    var best int 

    for result := range ch { 
     best = result 
    } 
    fmt.Println("Best result ", best) 
    // do something with best result here 

    //and communicate to main when you are done processing the result 
    doneProcessing <- true 

} 

func main() { 
    doneProcessing := make(chan bool) 
    stopSearch := make(chan bool) 

    // timer := time.NewTimer(time.Millisecond * 2000) 
    timer := time.NewTimer(time.Millisecond * 12) 

    ch := make(chan int) 

    go runSearch(1000, ch, stopSearch) 
    go awaitBestResult(ch, doneProcessing) 
    select { 
    case <-timer.C: 
     //If at the same time runsearch is also completed and trying to send a value ! 
     //So we hold a lock before sending value on the channel 
     mu.Lock() 
     if stopped == false { 
      stopped = true 
      stopSearch <- true 
      fmt.Println("Timer expired") 
     } 
     mu.Unlock() 

    case <-stopSearch: 
     fmt.Println("runsearch goroutine completed") 
    } 
    close(ch) 

    //Wait for your consumer to complete processing 
    <-doneProcessing 
    //Safe to exit now 
} 

オンplayground。両方のシナリオを観察するようにtimerの値を変更します。

関連する問題