2012-02-13 10 views
1

while文の代わりにstatementでparallelを使用したいと思います。私がParallel Forのサンプルを見ると、既知または可変のカウントだけで実行されます。Whileの代わりにTPLでParallel Forを使用する方法

しかし、私のループが何回実行され、実行時に変数にリンクすることができないのか分かりません。

私はTPLと古典的なコードで簡単なパフォーマンステストをしようとしています。だから、デクリメント操作でモジュラスを計算するモジュラスクラスを書いています。 My機能は

long FindModulus(long n, int i) 
{ 
    while (n >= i) 
     n -= i; 
    return n; 
} 

のように私の目標は、ループ

並列で、このループを交換され、また、私はifと休憩文を使用して並列に使用することができます学びたいです。

私はnの値がすべてのスレッドで変更されますので、私はロックが必要になると思いますが、何回ループわからない場合は、任意のコードサンプルは、事前

+3

方が良い例を投稿することができますか? –

+0

定義を追加しました、遅れて申し訳ありません、ネットワークに問題がありました – accfews

+0

まだ現実的ではないので、Foo()はループやロックを必要としません。 –

答えて

2

ループ内で作業していないので、どのような例も考案されています。しかし、あなたが主張する場合は、ここで(同期オーバーヘッドが作業自体よりも大きくなっているので、それは、同期バージョンよりも遅くなります)という考えを伝える例です。

long _n; 
int _i; 
long _mod; 

long FindModulusParallel(long n, int i) 
{ 
    _mod = _n = n; 
    _i = i; 

    var actions = Enumerable.Range(0, Environment.ProcessorCount) 
          .Select<int,Action>(j => Subtract).ToArray(); 
    Parallel.Invoke(actions); 

    return _mod; 
} 

void Subtract() 
{ 
    while (Interlocked.Add(ref _n, -_i) >= 0) 
     Interlocked.Add(ref _mod, -_i); 
} 
4

おかげでいただければ幸いですParallel.Forは渡すことはできません。しかし、あなたは簡単なタスクを使用して自分自身でそれを行うことができます。

object syncRoot = new object(); 
bool finished = false; 
private bool Finished() 
{ 
    // or implement any other logic to evaluate whether loop has finished 
    // but thread safe 
    lock (this.syncRoot) 
    { 
     return this.finished; 
    } 
} 

... 

List<Task> tasks = new List<Task>(); 
while (this.Finished()) 
{ 
    var task = new Task(() => 
    { 
     // implement your loop logic here 
    }) 
    task.Start(); 
    tasks.Add(task); 
} 

Task.WaitAll(tasks); 
+2

パラレルクラスとタスクは異なるものです。最初のものは、利用可能なプロセッサユニット上での効果的な実行を保証します。後者は、特定のタスクスケジューラ上での効果的な実行を保証します。 – Polity

4

私は

以下
public static class MyParallel 
{ 
    public static void While(Func<bool> condition, Action action) 
    { 
     Parallel.ForEach(WhileTrue(condition), _ => action()); 
    } 

    static IEnumerable<bool> WhileTrue(Func<bool> condition) 
    { 
     while (condition()) yield return true; 
    } 
} 

ようMyParallelクラスを作成し、このようにそれを使用します。

int i=0; 
MyParallel.While( 
    () => { 
     lock (SomeLockObject) 
     { 
      return i++<10; 
     } 
    }, 
    () => Console.WriteLine("test") 
); 

(あなたがそれらを変更した場合)共有オブジェクトをロックすることを忘れないでくださいはcondition/actionで使用

2

Parallel.Forは、例えば参照変数またはのFuncを受け取ることができませんので、我々は、良いol 'タスクを使うことに限られていました。ここでの例は次のとおり

int n = 100; 
int i = 3; 
int accum = 0; 
object logicLock = new object(); 
Random rand = new Random(); 

void Main() 
{ 
    // No point of having more tasks than available cores. 
    int maxTasks = 4; 
    Task[] tasks = new Task[maxTasks]; 
    int count = 0; 
    while(this.CheckCondition()) 
    { 
     int index = count; 
     if(count++ >= maxTasks) 
     { 
      Console.WriteLine("Waiting for a task slot"); 
      index = Task.WaitAny(tasks); 
     } 

     Console.WriteLine("Executing a task in slot: {0}", index); 
     tasks[index] = Task.Factory.StartNew(LoopLogic); 
    } 

    Console.WriteLine("Done"); 
} 

public void LoopLogic() 
{ 
    lock(logicLock) 
    { 
     accum += i; 
    } 

    int sleepTime = rand.Next(0, 500); 
    Thread.Sleep(sleepTime); 
} 

public bool CheckCondition() 
{ 
    lock(logicLock) 
    { 
     return (n - accum) >= i; 
    } 
} 

結果:スロット内のタスクを実行する2
:1
スロットでタスクを実行する:スロット内のタスクを実行する0

スロットでタスクを実行します。 2
Sでタスクを実行するタスクスロット
を待って:スロット内のタスクを実行するタスクスロット
を待っ3
たくさん:1
スロットにおけるタスクの実行タスクスロット
を待っている:3
スロットにタスクを実行するタスクスロット
を待っている:1
スロットでタスクを実行するタスクスロット
のを待ちました: 3
スロットにタスクを実行するタスクスロット
を待っ:0
スロットにタスクを実行するタスクスロット
を待って、同じの2
続き。
完了

+0

'Main()'に 'static'を加えてはなりません。コードや簡単な更新が見落とされていますか? – Fulproof

+0

そのコード例ではLINQPadを使用しました。 LINQPadでは静的な文字列args []などを定義する必要はありません。 Google:LINQPad –

関連する問題