2013-08-13 5 views
59

このコードは、呼び出された実行可能ファイルと同じフォルダ内のすべてのxmlファイルを選択し、コールバックメソッドの各結果に処理を非同期的に適用します(下の例ではファイル名のみが出力されます)。時間を使わずにすべてのゴルーチンが終了するのを待つ方法。スリープ?

メインメソッドが終了しないようにスリープメソッドを使用しないようにするにはどうすればよいですか?私は問題をチャネルの周りに私の頭をラップする(私はそれが、結果を同期するために何を仮定している)ので、任意の助けに感謝!

答えて

96

sync.WaitGroupを使用できます。リンクされた例を引用する:

package main 

import (
     "net/http" 
     "sync" 
) 

func main() { 
     var wg sync.WaitGroup 
     var urls = []string{ 
       "http://www.golang.org/", 
       "http://www.google.com/", 
       "http://www.somestupidname.com/", 
     } 
     for _, url := range urls { 
       // Increment the WaitGroup counter. 
       wg.Add(1) 
       // Launch a goroutine to fetch the URL. 
       go func(url string) { 
         // Decrement the counter when the goroutine completes. 
         defer wg.Done() 
         // Fetch the URL. 
         http.Get(url) 
       }(url) 
     } 
     // Wait for all HTTP fetches to complete. 
     wg.Wait() 
} 
+6

あなたはgoルーチンの外でwg.Add(1)を行う必要がありますか?私たちはDone()を延期する直前にそれを実行できますか? – sat

+9

sat、はい、sync.WaitGroup.Add docsに記述されている理由があります。 '''' 'Waitへの呼び出しの前に正のデルタを持つ呼び出しが発生している必要があります。通常これは、Addへの呼び出しが、ゴルーチンなどのイベントを作成する文の前に実行されることを意味します。 WaitGroupの例を参照してください。 '' ' – rslnx

+3

私のgoroutineは名前付き関数であり、WaitGroupを値としてコピーしてそれをコピーし、wg.Done()を無効にするため、このコードを変更するとデバッグセッションが長くなりました。これはポインタ&wgを渡すことで修正できますが、このようなエラーを防ぐより良い方法は、最初にWaitGroup変数をポインタとして宣言することです: 'var wg syncの代わりに' wg:= new(sync.WaitGroup) ' .WaitGroup'。 –

37

WaitGroupsはこれを行うための正式な方法です。ただし、完全性のために、WaitGroupsが導入される前に一般的に使用されていたソリューションがあります。基本的なアイデアは、チャンネルを使用して「完了しました」と言い、各ゴーイングルーチンが完了を報告するまでメインのゴルーチンを待たせることです。

func main() { 
    c := make(chan struct{}) // We don't need any data to be passed, so use an empty struct 
    for i := 0; i < 100; i++ { 
     go func() { 
      doSomething() 
      c <- struct{}{} // signal that the routine has completed 
     }() 
    } 

    // Since we spawned 100 routines, receive 100 messages. 
    for i := 0; i < 100; i++ { 
     <- c 
    } 
} 
+4

素敵なチャンネルのソリューションを見てよかった。追加のボーナス: 'doSomething()'が何か結果を返すのであれば、それをチャンネルに置くことができるので、2番目のforループで結果を収集して処理することができます(準備ができ次第) – andras

+0

ああ、 。 – joshlf

+2

これは、あなたが開始したいゴルチンの量を既に知っている場合にのみ機能します。何らかのHTMLクローラーを作成していて、ページ上のすべてのリンクに対して再帰的にゴルチンを開始するとどうなりますか? – shinydev

関連する問題