我在 C#/VS2010 中使用 Parallel.ForEach 循环进行处理,我有几个问题。
首先,我有一个进程需要从远程网络服务中提取信息,然后需要动态构建图像 (GDI)。
我有一个类将所有功能封装到一个对象中,该对象具有两个主要方法 Load() 和 CreateImage(),所有 GDI 管理/WebRequests 都“黑盒化”在该对象中。
然后我创建一个包含所有需要处理的对象的 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;
}
现在我的问题是:
- 鉴于列表中可能有一万个项目需要解析,上面的代码是解决这个问题的最佳方法吗?欢迎任何其他想法
- 我有一个问题,即当我开始该过程时,创建/加载对象和创建图像的速度非常快,但是在大约六百个对象之后,该过程开始抓取。它最终没有完成,这正常吗?
提前致谢:) 亚当
最佳答案
我不确定并行下载数据是个好主意,因为它会阻塞很多线程。而是将您的任务拆分为生产者和消费者。然后您可以分别并行化它们中的每一个。
这里是一个单一的生产者和多个消费者的例子。
(如果消费者比生产者快,你可以使用普通的 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 忙于图像处理。
关于c# - Parallel.ForEach 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6037118/