Parallel ForEach调用外部服务时限制为两个核

Parallel ForEach is Limited to Two Cores When Calling Exteranl Service

我正在尝试遍历包含 20,000 多条客户记录的列表。我正在使用 Parallel.ForEach() 循环来尝试加快处理速度。在委托函数内,我正在向外部 Web 服务发送 HTTP POST 以验证客户信息。这样做时,循环被限制为 2 个线程或逻辑核心。如果我尝试增加并行度,进程会抛出错误 "The underlying connection was closed: A connection that was expected to be kept alive was closed by the server"

这是使用外部进程时循环的默认行为还是接收网络服务器的限制?

我的代码相当简单:

Parallel.ForEach ( customerlist, new ParallelOptions {MaxDegreeOfParallelism = 3 },( currentCustomer ) =>
{
    if ( IsNotACustomer ( currentCustomer.TIN ) == true ) <--IsNotCustomer is where the HTTP POST takes place
    {
        ...Write data to flat file...
    }
});

如果我将 MaxDegreesOfParallelism 更改为 2,循环 运行 没问题。

此代码大约需要 80 分钟才能完成 20,000 条记录。虽然这并非不可接受,但如果我可以通过增加线程数来缩短该时间,那就更好了。

完整的异常消息(没有堆栈跟踪):

System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.

at System.Net.HttpWebRequest.GetResponse()

如有任何帮助,我们将不胜感激。

EDIT

HTTP POST 代码是:

HttpWebRequest request = ( HttpWebRequest )WebRequest.Create ( AppConfig.ESLBridgeURL + action );
request.Method = "POST";
request.GetRequestStream ( ).Write ( Encoding.UTF8.GetBytes ( body ), 0, body.Length );

Stream stream = request.GetResponse ( ).GetResponseStream ( );
StreamReader reader = new StreamReader ( stream );

output = reader.ReadToEnd ( );

URL 用于内部服务器 运行ning 专有 Web Sphere MQ 服务。其要点是检查内部数据源,看看我们是否与客户有关系。

我们 运行 我们每天在数百个站点的客户关系管理流程中采用相同的流程。所以我不认为存在任何许可问题,而且我确信这些 MQ 服务可以接受每个客户端的多个调用。

EDIT 2

更多的研究表明 2 个连接限制是有效的。但是,使用 ServicePointManager 可能能够绕过此限制。我找不到的是将 ServicePointManager 与 HttpWebRequests 结合使用的 C# 示例。

任何人都可以指出有效资源或提供代码示例吗?

您可能 运行 超出了默认的 2 个客户端限制。参见 System.Net.ServicePointManager.DefaultConnectionLimit on MSDN

The maximum number of concurrent connections allowed by a ServicePoint object. The default value is 2.

可能相关的问题:How Can I programmatically remove the 2 connection limit in WebClient?

感谢马特·斯蒂芬森和马特·乔丹为我指明了正确的方向。

我找到了一个将我的处理量减半的解决方案。我将继续调整以获得最佳结果,但这是我的结果。

我在应用程序配置文件中添加了以下内容:

<system.net>
    <connectionManagement>
        <add address="*" maxconnection="100"/>
    </connectionManagement>
</system.net>

然后我想出了如何使用 ServicePointManager 并设置以下内容:

int dop = Environment.ProcessorCount;
ServicePointManager.MaxServicePoints = 4;
ServicePointManager.MaxServicePointIdleTime = 10000;
ServicePointManager.UseNagleAlgorithm = true;
ServicePointManager.Expect100Continue = false;
ServicePointManager.DefaultConnectionLimit = dop * 10;

ServicePoint sp = ServicePointManager.FindServicePoint ( new Uri ( AppConfig.ESLBridgeURL ) );

对于我的开发机器,处理器数量是 8。

按原样,此代码使我能够在大约 45 分钟内处理我的 20,000 多条记录。