1

我想在语句中使用并行 for 而不是 while 语句。当我查看仅使用已知或变量计数的样本 Parallel For 运行时。

但我不知道我的循环将运行多少次,并且它无法在运行时将其链接到变量。

我将尝试使用 TPL 和经典代码进行简单的性能测试。所以我正在编写一个模数类,它通过减量操作计算模数。我的功能就像

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

我的目标是用 Parallel For 循环替换这个循环

而且我还想了解我可以将 Parallel For 与 if 和 break 语句一起使用。

我想我需要一个锁,因为 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,因此我们仅限于使用好的 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;
    }
}

结果:

在槽中执行任务: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 回答