如何在TPL中使用Parallel For而不是While
本文关键字:For While Parallel TPL | 更新日期: 2023-09-27 18:24:10
我想在语句中使用parallel for,而不是while语句。当我看到样本Parallel For运行时,只有一个已知的或可变的计数。
但我不知道我的循环会运行多少次,而且它无法在运行时将其链接到变量。
我将尝试使用TPL和经典代码进行简单的性能测试。所以我正在写一个模量类,它用递减运算来计算模量。我的功能就像
long FindModulus(long n, int i)
{
while ( n >= i )
n -= i;
return n;
}
我的目标是用Parallel For loop 替换这个循环
我还想学习是否可以将Parallel For与if and break语句一起使用。
我想我需要一个锁,因为n的值将在所有线程中更改,任何代码样本都将受到的赞赏
提前感谢
如果您不知道循环将通过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);
我会在下面写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
中使用的共享对象(如果您修改了它们)
由于您没有在循环中做任何工作,因此任何示例都是人为设计的。但如果你坚持,这里有一个例子传达了这个想法(它将比同步版本慢,因为同步开销大于工作本身):
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);
}
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
…更多的是一样的
完成