我用Parallel.For替换了代码中的for循环。性能提升是惊人的(1/3的运行时间)。我尝试使用数组来收集结果代码来解释共享资源。然后我在Parallel.For之外处理数组。这是最有效的方法吗?或者即使没有迭代可以共享相同的循环索引,阻塞仍然会发生吗?CompareExchange的表现会好得多吗?
int[] pageResults = new int[arrCounter];
Parallel.For(0, arrCounter, i =>
{
AlertToQueueInput input = new AlertToQueueInput();
input.Message = Messages[i];
pageResults[i] = scCommunication.AlertToQueue(input).ReturnCode;
});
foreach (int r in pageResults)
{
if (r != 0 && outputPC.ReturnCode == 0) outputPC.ReturnCode = r;
}
这取决于您在主循环中是否有任何(有价值的)副作用。
当outputPC.ReturnCode
是唯一的结果时,可以使用PLINQ:
outputPC.ReturnCode = Messages
.AsParallel()
.Select(msg =>
{
AlertToQueueInput input = new AlertToQueueInput();
input.Message = msg;
return scCommunication.AlertToQueue(input).ReturnCode;
})
.FirstOrDefault(r => r != 0);
这假设scCommunication.AlertToQueue()是线程安全的,并且您不想在第一个错误之后为剩余的项调用它。
请注意,PLinq中的FirstOrDefault()仅在Framework 4.5及更高版本中有效。
您可以替换:
foreach (int r in pageResults)
{
if (r != 0 && outputPC.ReturnCode == 0) outputPC.ReturnCode = r;
}
:
foreach (int r in pageResults)
{
if (r != 0)
{
outputPC.ReturnCode = r;
break;
}
}
这将在第一次失败时停止循环。
我喜欢David Arno的解决方案,但正如我所看到的,您可以通过将检查放入并行循环中并直接从它中断来提高速度。无论如何,如果任何迭代失败,则将主代码置于失败状态,因此不需要进一步的迭代。
像这样:
Parallel.For(0, arrCounter, (i, loopState) =>
{
AlertToQueueInput input = new AlertToQueueInput();
input.Message = Messages[i];
var code = scCommunication.AlertToQueue(input).ReturnCode;
if (code != 0)
{
outputPC.ReturnCode = code ;
loopState.Break();
}
});
乌利希期刊指南1:
如果您需要保存所有迭代的结果,您可以这样做:
int[] pageResults = new int[arrCounter];
Parallel.For(0, arrCounter, (i, loopState) =>
{
AlertToQueueInput input = new AlertToQueueInput();
input.Message = Messages[i];
var code = scCommunication.AlertToQueue(input).ReturnCode;
pageResults[i] = code ;
if (code != 0 && outputPC.ReturnCode == 0)
outputPC.ReturnCode = code ;
});
它将使您免于foreach
循环,这是一个改进,尽管是一个小改进。
乌利希期刊指南2:
刚刚发现这篇文章,我认为自定义并行也是一个很好的解决方案。但这是你自己决定是否适合你的任务。