我在C#/ VS2010中使用Parallel.ForEach循环进行处理,我有几个问题。
首先,我有一个流程需要从远程Web服务中提取信息,然后需要动态构建映像(GDI)。
我有一个类将所有功能封装到一个对象中,使用两个主要方法Load()和CreateImage(),并在此对象中包含所有GDI管理/ WebRequests“blackboxed”。
然后我创建一个包含所有需要处理的对象的GenericList,并使用以下代码遍历列表:
try
{
Parallel.ForEach(MyLGenericList, ParallelOptions, (MyObject, loopState) =>
{
MyObject.DoLoad();
MyObject.CreateImage();
MyObject.Dispose();
if (loopState.ShouldExitCurrentIteration || loopState.IsExceptional)
loopState.Stop();
});
}
catch (OperationCanceledException ex)
{
// Cancel here
}
catch (Exception ex)
{
throw ex;
}
现在我的问题是:
提前致谢:) 亚当
答案 0 :(得分:4)
我不确定并行下载数据是个好主意,因为它会阻塞很多线程。将您的任务拆分为生产者和消费者。然后你可以分别并行化它们。
以下是单个生产者和多个消费者的示例 (如果消费者比生产者更快,你可以使用普通的foreach而不是parallel.ForEach)
var sources = BlockingCollection<SourceData>();
var producer = Task.Factory.CreateNew(
() => {
foreach (var item in MyGenericList) {
var data = webservice.FetchData(item);
sources.Add(data)
}
sources.CompleteAdding();
}
)
Parallel.ForEach(sources.GetConsumingPartitioner(),
data => {
imageCreator.CreateImage(data);
});
(GetConsumingPartitioner扩展是ParallelExtensionsExtras)
的一部分修改更完整的示例
var sources = BlockingCollection<SourceData>();
var producerOptions = new ParallelOptions { MaxDegreeOfParallelism = 5 };
var consumerOptions = new ParallelOptions { MaxDegreeOfParallelism = -1 };
var producers = Task.Factory.CreateNew(
() => {
Parallel.ForEach(MyLGenericList, producerOptions,
myObject => {
myObject.DoLoad()
sources.Add(myObject)
});
sources.CompleteAdding();
});
Parallel.ForEach(sources.GetConsumingPartitioner(), consumerOptions,
myObject => {
myObject.CreateImage();
myObject.Dispose();
});
使用此代码,您可以优化并行下载量,同时保持CPU忙于图像处理。
答案 1 :(得分:1)
当循环体所做的工作是CPU绑定时,使用默认设置的Parallel.ForEach
方法效果最佳。如果您同步阻止或将工作交给另一方,则调度程序认为CPU仍然不忙并且不断填写更多任务,并努力使用系统中的所有CPU。
在您的情况下,您需要选择合理数量的重叠下载并行发生,并在ForEach
选项中设置该值,因为您不会在循环中使CPU饱和。