C# 平行问题
我正在使用C#/VS2010中的Parallel.ForEach循环进行处理,我有几个问题 首先,我有一个流程,需要从远程Web服务提取信息,然后需要动态构建映像(GDI) 我有一个类,它使用两个主要方法Load()和CreateImage()将所有功能封装到一个对象中,所有GDI管理/WebRequests都在这个对象中“黑盒” 然后,我创建一个GenericList,其中包含需要处理的所有对象,并使用以下代码遍历该列表:C# 平行问题,c#,.net,multithreading,task-parallel-library,C#,.net,Multithreading,Task Parallel Library,我正在使用C#/VS2010中的Parallel.ForEach循环进行处理,我有几个问题 首先,我有一个流程,需要从远程Web服务提取信息,然后需要动态构建映像(GDI) 我有一个类,它使用两个主要方法Load()和CreateImage()将所有功能封装到一个对象中,所有GDI管理/WebRequests都在这个对象中“黑盒” 然后,我创建一个GenericList,其中包含需要处理的所有对象,并使用以下代码遍历该列表: try { Parallel.
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;
}
现在我的问题是:
Adam当循环体所做的工作受CPU限制时,带有默认设置的
Parallel.ForEach
方法最有效。如果您正在同步阻止或将工作移交给另一方,调度程序会认为CPU仍然不忙,并不断填充更多任务,试图使用系统中的所有CPU
在您的情况下,您只需选择一个合理数量的并行重叠下载,并在
ForEach
选项中设置该值,因为循环不会使CPU饱和。我不确定并行下载数据是一个好主意,因为它会阻塞大量线程。将任务分为生产者和消费者。然后您可以分别对它们进行并行化
以下是一个单一生产商和多个消费者的示例。(如果消费者的速度比生产者快,您可以使用普通的foreach而不是parallel.foreach)
var sources=BlockingCollection();
var producer=Task.Factory.CreateNew(
() => {
foreach(MyGenericList中的变量项){
var data=webservice.FetchData(项);
来源.添加(数据)
}
sources.CompleteAdding();
}
)
Parallel.ForEach(sources.GetConsumingPartitioner(),
数据=>{
CreateImage(数据);
});
(GetConsumingPartitioner扩展是的一部分)
编辑一个更完整的示例
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();
});
var sources=BlockingCollection();
var ProduceProptions=new ParallelOptions{MaxDegreeOfpParallelism=5};
var consumerOptions=new ParallelOptions{maxdegreeofpparallelism=-1};
var producers=Task.Factory.CreateNew(
() => {
Parallel.ForEach(我的通用列表、产品目录、,
myObject=>{
myObject.DoLoad()
sources.Add(myObject)
});
sources.CompleteAdding();
});
Parallel.ForEach(sources.GetConsumingPartitioner(),consumerOptions,
myObject=>{
myObject.CreateImage();
myObject.Dispose();
});
使用此代码,您可以优化并行下载量,同时让cpu忙于图像处理。有一个catch块除了抛出它捕获的异常之外什么都不做,这有什么意义?嗨,这刚好足够显示我在may应用程序中所做的事,显然,没有人对我的错误处理感兴趣,因为它与问题无关:)这很公平,但我会完全忽略catch块(显然是第二个块)——特别是因为你只是在草拟一个示例。嗨,谢谢你的帮助。在上面的例子中,我将不得不等待,直到从webservice检索到每个项目,这可能需要一段时间。我希望在一个单独的线程中填充我的对象/创建图像,每次5个,因为它通过列表来加快速度。不,示例中有一个线程连续检索项目。一旦取回一个项目,消费者部分就开始处理它(同时取回下一个项目)。如果您认为同时获取五个项目更快,只需使用多个生产者即可。(我将更新示例)再次感谢您的帮助;我遇到的一个问题是ParallelExtensionsExtras.dll,我已经下载了它,添加了一个引用,但是GetConsumingPartitioner似乎从未出现过。我得到了一份可以信赖的工作,没问题。有什么想法吗?好的,谢谢;这似乎是做这件事的正确方法
code
Parallel.ForEach(BlockingCollectionExtensions.GetConsumingPartitioner(sources),consumerOptions,myObject=>{
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();
});