3 .net c# multithreading parallel-extensions
Parallel.ForEach没有旋转新线程
大家好,我们有一个非常密集的IO操作,我们使用Microsoft的.NET Framework并行扩展中的Parallel.ForEach编写.我们需要删除大量文件,并且我们将要删除的文件表示为列表列表.每个嵌套列表中都有1000条消息,我们有50条这样的列表.这里的问题是,当我查看之后的日志时,我只看到在Parallel.ForEach块内执行一个线程.
这是代码的样子:
List<List<Message>> expiredMessagesLists = GetNestedListOfMessages();
foreach (List<Message> subList in expiredMessagesLists)
{
Parallel.ForEach(subList, msg =>
{
try
{
Logger.LogEvent(TraceEventType.Information, "Purging Message {0} on Thread {1}", msg.MessageID, msg.ExtensionID, Thread.CurrentThread.Name);
DeleteMessageFiles(msg);
}
catch (Exception ex)
{
Logger.LogException(TraceEventType.Error, ex);
}
});
}
Run Code Online (Sandbox Code Playgroud)
我写了一些示例代码,它具有更简单的数据结构,没有IO逻辑,我可以看到在Parallel.ForEach块中执行的几个不同的线程.我们在上面的代码中使用Parallel.ForEach做错了吗?它可能是绊倒它的列表列表,还是IO操作存在某种线程限制?
有几种可能性.
首先,在大多数情况下,Parallel.ForEach不会产生新的线程.它使用.NET 4 ThreadPool(所有TPL都有),并将重用ThreadPool线程.
话虽这么说,Parallel.ForEach使用基于传递给它的List大小的分区策略.我的第一个猜测是你的"外部"列表有很多消息,但内部列表只有一个Message实例,所以ForEach分区只使用一个线程.使用一个元素,Parallel足够聪明,只需使用主线程,而不是将工作旋转到后台线程.
通常,在这种情况下,最好并行化外部循环,而不是内部循环.这通常会为您提供更好的性能(因为您将拥有更大的工作项),尽管如果不了解循环大小加上工作单元的大小,很难知道.您也可以将内循环和外循环并行化,但如果没有分析,很难说出什么是最佳选择.
另一种可能性:
尝试使用[Thread.ManagedThreadId][1]而不是Thread.CurrentThread.Name进行日志记录.由于Parallel使用ThreadPool线程,"名称"在多个线程中通常是相同的.当你实际上使用多个线程时,你可能认为你只使用一个线程....
| 归档时间: |
|
| 查看次数: |
3483 次 |
| 最近记录: |