c# - Parallel.ForEach 问题

标签 c# .net multithreading task-parallel-library

我在 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;
        }

现在我的问题是:

  1. 鉴于列表中可能有一万个项目需要解析,上面的代码是解决这个问题的最佳方法吗?欢迎任何其他想法
  2. 我有一个问题,即当我开始该过程时,创建/加载对象和创建图像的速度非常快,但是在大约六百个对象之后,该过程开始抓取。它最终没有完成,这正常吗?

提前致谢:) 亚当

最佳答案

我不确定并行下载数据是个好主意,因为它会阻塞很多线程。而是将您的任务拆分为生产者和消费者。然后您可以分别并行化它们中的每一个。

这里是一个单一的生产者和多个消费者的例子。
(如果消费者比生产者快,你可以使用普通的 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/

相关文章:

c# - 如何在页面之间传递值? (Windows 手机)

c# - 数字组合

c# - 是否可以覆盖配置中的硬编码事务超时?

C# WinForms 隐藏加密 key

java - 如何使用 ExecutorService 等待所有线程完成?

Java等待线程在通知后不会恢复

c# - 在 VS Package 项目中获取 dte2 或 TeamFoundationServerExt 对象?

.net - InputFile组件图片上传问题

.net - 通过 SDK 将项目添加到 TFS 中的全局列表

java - 当线程中断时继续 hibernate 剩余时间