2017-12-28 7 views
1

私はGolangのforループを使って同時に1000個のゴルーチンを開始すると考えています。
問題は次のとおりです。すべてのgoroutineが実行されていることを確認する必要があります。
これを確認するのにチャンネルを使用することは可能ですか?Golangでは、チャンネルで多くのゴルーチンを扱う方法

構造はちょっと、このようなものです:

func main { 
    for i ... { 
     go ... 
     ch? 
    ch? 
} 
+2

あなたはゴルーチンが終了するのを待っていますか?もしそうなら、 'sync.WaitGroup'を使うことができます。 https://golang.org/pkg/sync/#WaitGroupを参照してください。 –

+0

私はこの仕事を理解していないかもしれません。 1000種類の異なるゴルーチンがありますか?そうでない場合、同じタスクを実行すると、どのアプリケーションが実行されたのかは異なりますか? –

答えて

0

はい、thisを試してみてください。

package main 

import (
    "fmt" 
) 

const max = 1000 

func main() { 
    for i := 1; i <= max; i++ { 
     go f(i) 
    } 

    s := 0 
    for i := 1; i <= max; i++ { 
     s += <-ch 
    } 

    fmt.Println(s) 
} 

func f(n int) { 
    // do a job here 
    ch <- n 
} 

var ch = make(chan int, max) 

出力:

500500 
+0

これは動作し、OPの制約を満たしていますが、これはベストプラクティスではありません。このアドホックなアプローチの問題は、保守性と拡張性です。 'WaitGroup'は、この正確な問題に取り組むために設計されました。 –

+0

@KshitijSaraogi:ベストプラクティスは、手元の問題に非常に依存します。例:1000個のゴルーチンが特定の計算をしてからメインのゴルーチンに 'int'の結果を送る必要があると想像してください。これがベストプラクティスです。 –

2

@Andyあなたはこれを達成するためにsync.WaitGroupを使用することができます述べたように。以下は例です。コードが自明であることを願っています。

package main 

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

func dosomething(millisecs int64, wg *sync.WaitGroup) { 
    defer wg.Done() 
    duration := time.Duration(millisecs) * time.Millisecond 
    time.Sleep(duration) 
    fmt.Println("Function in background, duration:", duration) 
} 

func main() { 
    arr := []int64{200, 400, 150, 600} 
    var wg sync.WaitGroup 
    for _, n := range arr { 
    wg.Add(1) 
    go dosomething(n, &wg) 
    } 
    wg.Wait() 
    fmt.Println("Done") 
} 
+1

おそらく、 'dosomething()'の開始時に 'woo.Done()'を延期することは、もっと慣れないでしょう。 – biosckon

0

私はあなたがパターンに従うことを示唆しています。並行性とチャネルは良いですが、悪い方法で使用すると、プログラムが予想よりも遅くなる可能性があります。複数のゴールールとチャネルを処理する簡単な方法は、ワーカー・プール・パターンによるものです。

は、この単純な例では、hereから取られ

// In this example we'll look at how to implement 
// a _worker pool_ using goroutines and channels. 

package main 

import "fmt" 
import "time" 

// Here's the worker, of which we'll run several 
// concurrent instances. These workers will receive 
// work on the `jobs` channel and send the corresponding 
// results on `results`. We'll sleep a second per job to 
// simulate an expensive task. 
func worker(id int, jobs <-chan int, results chan<- int) { 
    for j := range jobs { 
     fmt.Println("worker", id, "started job", j) 
     time.Sleep(time.Second) 
     fmt.Println("worker", id, "finished job", j) 
     results <- j * 2 
    } 
} 

func main() { 

    // In order to use our pool of workers we need to send 
    // them work and collect their results. We make 2 
    // channels for this. 
    jobs := make(chan int, 100) 
    results := make(chan int, 100) 

    // This starts up 3 workers, initially blocked 
    // because there are no jobs yet. 
    for w := 1; w <= 3; w++ { 
     go worker(w, jobs, results) 
    } 

    // Here we send 5 `jobs` and then `close` that 
    // channel to indicate that's all the work we have. 
    for j := 1; j <= 5; j++ { 
     jobs <- j 
    } 
    close(jobs) 

    // Finally we collect all the results of the work. 
    for a := 1; a <= 5; a++ { 
     <-results 
    } 
} 

以下のコードをよく見てください。また、resultsチャネルは、障害通知などのジョブを実行しているすべてのgoルーチンを追跡するのに役立ちます。

関連する問題