可扩展应用程序,提高并行性能

时间:2014-06-12 09:41:34

标签: .net task-parallel-library

我有一个包含100,000个用户的列表,我通过传递用户ID来从各种Web源(REST API)获取这些用户的相关数据。

我首先将100,000个用户划分为块,然后并行调用API以获取数据,下面是片段。

ParallelOptions po = new ParallelOptions
    {
        po.MaxDegreeOfParallelism = -1;
    };


Parallel.ForEach(listSubscriberEmail, po, (subscriber) =>
    {    
        ProcessEachSubscriber(subscriber);
    });

listSubscriberEmail是用户列表,方法ProcessEachSubscriber调用各种AP​​I。

在4芯机器上花了大约1个小时。

我将代码库迁移到8核机器,但所用的时间仍然相同。

我想我编写代码的方式基本上应该减少时间,因为理想情况下它现在应该在8个核心上产生8个任务......任何想法为什么会出现这种情况?

1 个答案:

答案 0 :(得分:1)

我认为你正朝着正确的方向前进。 首先,我不会设置MaxDegreeOfParallelism无限制。这可能会使你的线程池匮乏并引发数百个线程做得很少。 一种常见的方法是将parrallelism设置为您的核心数:

ParallelOptions loopOptions = new ParallelOptions
{
    MaxDegreeOfParallelism = Environment.ProcessorCount,
};

您可以将这些选项传递给Parallel.For重载。

其次,您提到从REST API获取用户数据。 据推测,这是一个网络呼叫,因此您需要考虑两个项目:

1)系统默认允许并行使用网络连接数,此默认值很小(我认为是两个或四个)。您可以通过调用:

来覆盖它
ServicePointManager.DefaultConnectionLimit = n;

进程中的任何位置(ServicePointManager是那些知道它应该做什么的'环境上下文'接口之一。)

在这种情况下,

' n '需要进行一些实验,以了解应用程序的最佳网络带宽以及REST api响应的程度。 (只是为了给你一个想法,我有一个类似的过程,这个设置为16,但我正在调用一个公共REST api,它可能非常强大,并且意味着可以很好地扩展。)

2)利用async中的新WebClient方法,以便在等待网络I / O时释放并行线程以执行其他工作。正如 I3arnon 所说,网络I / O不受CPU限制,因此在其上投入额外的内核不会有任何区别。

最后,与任何性能优化一样,添加一些准确测量单个操作时间的日志记录,并查看瓶颈所在。你会经常感到惊讶。在投入大量并行呼叫之前,请关注这些点。