1

while ステートメントの代わりにステートメントで parallel for を使用したい。サンプルを見ると、Parallel For は既知の (または変数の) カウントのみで実行されます。

しかし、ループが何回実行されるかはわかりません。実行時にループを変数にリンクすることはできません。

TPL と従来のコードを使用して、簡単なパフォーマンス テストを試みます。だから私はデクリメント操作でモジュラスを計算するモジュラスクラスを書いています。私の機能は

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

私の目標は、このループを Parallel For ループに置き換えることです

また、if ステートメントと break ステートメントで Parallel For を使用できるかどうかも知りたいです。

すべてのスレッドで n の値が変更されるため、ロックが必要になると思います。コードサンプルをいただければ幸いです

前もって感謝します

4

4 に答える 4

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);
于 2012-02-13T08:09:10.410 に答える
4

MyParallel以下のようにクラスを書きます

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;
    }
}

このように使用します。

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

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

于 2012-02-13T08:13:30.800 に答える
2

たとえば Parallel.For は参照変数や Func を受け取ることができないため、古き良きタスクの使用に限定されます。次に例を示します。

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;
    }
}

結果:

スロット内タスク実行中:0 スロット内
タスク実行中:1 スロット内
タスク実行中:2 スロット内
タスク実行中:3
タスクスロット待機中 スロット
内タスク実行中:2
タスクスロット待機中 スロット
内タスク実行中:1
タスクスロット待ち
スロット内タスク実行中:3
タスクスロット待ちスロット
内タスク実行:1
タスクスロット待ちスロット
内タスク実行:0
タスクスロット待ちスロット
内タスク実行:3
タスク スロットを待機
中 スロットでタスクを実行中: 2
... さらに同じ。
終わり

于 2012-02-13T08:48:48.833 に答える
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);
}
于 2012-02-13T12:38:29.657 に答える