【问题标题】:Parallel ForEach is Limited to Two Cores When Calling Exteranl Service调用外部服务时并行 ForEach 仅限于两个核心
【发布时间】:2016-04-09 03:18:05
【问题描述】:

我正在尝试遍历包含 20,000 多个客户记录的列表。我正在使用 Parallel.ForEach() 循环来尝试加快处理速度。在委托函数中,我正在向外部 Web 服务发送 HTTP POST 以验证客户信息。这样做时,循环被限制为 2 个线程或逻辑核心。如果我尝试增加并行度,该过程会抛出错误“底层连接已关闭:预期保持活动状态的连接已被服务器关闭”

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

我的代码相当简单:

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:底层连接已关闭:A 预期保持活动的连接被 服务器。

在 System.Net.HttpWebRequest.GetResponse()

任何帮助将不胜感激。

编辑

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 指向运行专有 WebSphere MQ 服务的内部服务器。其要点是检查内部数据源,以查看我们是否与客户有关系。

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

编辑 2

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

谁能给我指出一个有效的资源或提供一个代码示例?

【问题讨论】:

  • 很可能是接收 Web 服务器的限制,或者可能是许可限制,具体取决于您调用的实际 Web 服务。也可能是 IsNotACustomer 中的非线程安全代码,因此如果您验证 Web 服务器允许来自同一源计算机的 2 个以上同时连接,您可能需要发布该代码。
  • @MattJordan 请查看我的编辑,谢谢
  • WebSphere MQ 服务器上的 MAXINST 和 MAXINSTC 配置是什么? MAXINST 几乎可以肯定很高,因为您从数百个不同的站点访问它,但每个客户端的 MAXINSTC 仍然可能是一个问题。 ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.con.doc/…

标签: c# task-parallel-library


【解决方案1】:

您可能会遇到默认的 2 个客户端限制。见System.Net.ServicePointManager.DefaultConnectionLimiton MSDN

ServicePoint 对象允许的最大并发连接数。默认值为 2。

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

【讨论】:

    【解决方案2】:

    感谢 Matt Stephenson 和 Matt Jordan 为我指明了正确的方向。

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

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

    <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 多条记录。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多