Parallel.ForEach问题

use*_*136 9 .net c# multithreading task-parallel-library

我在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;
        }
Run Code Online (Sandbox Code Playgroud)

现在我的问题是:

  1. 鉴于列表中可能有一万个项要解析,上面的代码是最好的方法吗?任何其他想法更受欢迎
  2. 我有一个问题,当我开始进程时,对象被创建/加载并且图像创建得非常快,但是在大约六百个对象之后,进程开始爬行.它最终没有完成,这是正常的吗?

在此先感谢:)亚当

adr*_*anm 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);
                 });
Run Code Online (Sandbox Code Playgroud)

( 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();
    });
Run Code Online (Sandbox Code Playgroud)

使用此代码,您可以优化并行下载量,同时保持 CPU 忙于图像处理。