2012-01-11 38 views
2

XML要素を返すメソッドがありますが、そのメソッドは終了して値を返すのに時間がかかります。複数のメソッドを同時に複数回実行する#

私が今持っていることは

foreach (var t in s) 
{ 
    r.add(method(test)); 
} 

ですが、これが唯一の以前の1が終了した後、次のステートメントを実行します。私はそれを同時に動かすことができますか?

+0

は 'r'と' add'と 'method'と' test'スレッドセーフですか? – Yahia

答えて

5

あなたはこのためにタスクを使用することができるはずです。

//first start a task for each element in s, and add the tasks to the tasks collection 
var tasks = new List<Task>(); 
foreach(var t in s) 
{ 
    tasks.Add(Task.Factory.StartNew(method(t))); 
} 

//then wait for all tasks to complete asyncronously 
Task.WaitAll(tasks); 

//then add the result of all the tasks to r in a treadsafe fashion 
foreach(var task in tasks) 
{ 
    r.Add(task.Result); 
} 

EDIT 上記のコードでいくつかの問題があります。動作するバージョンについては、以下のコードを参照してください。ここでは、可読性問題のためにLINQを使用するループを書き直しました(問題の原因となるラムダ式内のtのクロージャを回避するための最初のループの場合)。

var tasks = s.Select(t => Task<int>.Factory.StartNew(() => method(t))).ToArray(); 

//then wait for all tasks to complete asyncronously 
Task.WaitAll(tasks); 

//then add the result of all the tasks to r in a treadsafe fashion 
r = tasks.Select(task => task.Result).ToList(); 
+0

エラー 'System.Threading.Tasks.TaskFactory.StartNew(System.Action)'に最適なオーバーロードされたメソッドに無効な引数があります\t tasks.Add(Task.Factory.StartNew(method(t )))); – ikel

+0

私のコードにいくつかの問題があります。あなたのためにそれを編集する2分を与えてください。 –

+0

ikel - 私の編集を参照してください。コードもちょっと整理されました:) –

4

Parallel.ForEachを使用すると、複数のスレッドを使用して並列実行することができます。呼び出されるすべてのコードがスレッドセーフであり、並列に実行できることを確認する必要があります。

Parallel.ForEach(s, t => r.add(method(t)); 
+0

これは新しいものです。以前はこれを使用したことがありませんでした。私は試してみます。ありがとうございました – ikel

+4

これはほぼOKですが、ここでの問題はrのaddメソッドスレッドセーフではなく、さまざまなスレッドからリストに追加すると**問題が発生します。 –

0

私はループ内の共有コレクションを更新しています。これは、ループを並列に実行すると、複数のスレッドが同期していないコレクション(がListなどであると仮定します)を同時に更新しようとするため、データの競合が発生し、矛盾した状態が発生するためです。並行して、正しく実行するに

、あなたはロックのステートメント内のコードのセクションをラップする必要があります。

object locker = new object(); 
Parallel.Foreach (s, 
    t => 
    { 
     lock(locker) r.add(method(t)); 
    }); 

しかし、これは実行が実際にシリアルになります、各スレッドがロックを取得する必要があるためと同時に2つのスレッドがそうすることはできません。

各スレッドのローカルリストを作成し、そのリストに部分的な結果を追加し、すべてのスレッドが完了したときに結果をマージする方がよい場合があります。たぶん@ØyvindKnobloch-Bråthenの2番目の解決策は、method(t)がこの場合のCPUホッグであると仮定すれば、最良の方法です。

0

修正この質問に対する正しい答えに

​​へ 変更

tasks.Add(Task.Factory.StartNew(method(t);)); 

関連する問題