Linq AsParallel()不能过早地处理SoapHttpClientProtocol对象
本文关键字:处理 SoapHttpClientProtocol 对象 AsParallel 不能 Linq | 更新日期: 2023-09-27 18:26:18
在我正在开发的ASP.Net MVC 4 web应用程序中。我有一个页面,它基本上通过从SOAP服务获取数据来生成报告。
我的代码基本上看起来像这个
List<CustomThings> serverInfos = ServerInfos;
serverInfos.AsParallel().ForAll(srvInfo =>
{
SoapHttpClientProtocol soapProxy = CreateProxy(srvInfo);
//call make soap calls through the soap client
//store results in the proper places
}
我之所以在这里使用AsParallel,是因为以串行方式通过HTTP进行多个请求需要花费很长时间。我应该指出这段代码确实有效,尽管偶尔。
有没有可能事情正在以一种不可预测的方式被处理,而PLINQ并不是我在这里尝试做的一个好的解决方案?
另一个线程问题是否可能导致导致soap客户端"放弃"的错误?
其他信息
这个特殊的soap代理正在与ArcGIS服务器进行通信。通常,您可以检查服务器日志,查看特定请求何时启动以及请求是否失败。这些日志中没有显示任何内容。
下面是我从AsParallel代码中获得的内部异常堆栈跟踪的一个示例。
异常:System.AggregateException:出现一个或多个错误。--->System.Net.WebException:基础连接已关闭:本应保持活动状态的连接被服务器。--->System.IO.IOException:无法从传输连接:现有连接被强制关闭远程主机。--->System.Net.Sockets.SocketException:现有连接被位于的远程主机强制关闭System.Net.Socket.Socket.Receive(Byte[]缓冲区,Int32偏移量,Int32大小,SocketFlags SocketFlags)System.Net.Sockets.NetworkStream.Read(Byte[]缓冲区,Int32偏移量,Int32大小)---内部异常堆栈跟踪结束---位于System.Net.Sockets.NetworkStream.Read(Byte[]缓冲区,Int32偏移量,Int32大小),位于System.Net.PooledStream.Read(Byte[]缓冲区,Int32偏移,Int32大小)System.Net.Connection.SyncRead(HttpWebRequest请求,布尔值userRetrievedStream,布尔probeRead)--内部异常结束堆栈跟踪--在System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest请求)System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest请求)System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(字符串methodName,Object[]参数)ESRI.ArcGIS.SOAP.FeatureServerProxy.Query(Int32 LayerOrTableID,字符串DefinitionExpression、QueryFilter QueryFilter、ServiceDataOptionsServiceDataOptions,字符串GdbVersion,双最大允许偏移量)在System.Linq.Palallel.SelectQueryOperator
2.SelectQueryOperatorResults.GetElement(Int32 index) at System.Linq.Parallel.QueryResults
1.get_Item(Int32索引)在位于的System.Linq.Parallel.PartitionedDataSource1.ListContiguousIndexRangeEnumerator.MoveNext(T& currentElement, Int32& currentKey) at System.Linq.Parallel.PipelineSpoolingTask
2.SpoolingWork()位于的System.Linq.Parallel.SpoolingTaskBase.Work()位于的System.Linq.Parallel.QueryTask.BaseWork(对象未使用)System.Linq.Parallel.QueryTask。<。cctor>b__0(对象o)位于的System.Threading.Tasks.Task.InerInvoke()System.Threading.Tasks.Task.Execute()
PLINQ甚至不知道您的连接对象存在。它无法关闭它。
仔细阅读信息:
远程主机已强制关闭现有连接。
服务器以意外的方式关闭了连接。你的客户没有过错。
准确解释异常是一项必不可少的调试技能。这些信息就在异常消息中。
也许你产生了太多的负载。设定可持续的平行度。默认的启发式算法是针对CPU工作,而不是针对IO
.WithDegreeOfParallelism(10)
服务器关闭了本应保持活动状态的连接。
这可能意味着服务器不支持HTTP保持活动。
我不认为您对Soap HTTP请求的AsParallel
做了什么严重的错误,也不认为这是线程问题。
然而,并行请求显然会将您的客户端/服务器推到连接限制的数量,这就是为什么您会看到连接被关闭的原因。
我敢打赌,您的客户端、服务器或两者都没有配置为处理您正在发出的并发连接的数量。这就是为什么当您以串行方式运行请求时它会起作用。
我想您没有访问服务器配置的权限,所以您可以做的一件事是通过设置ParallelEnumerable.WithDegreeOfParallelism
设置来控制同时向服务器发出的并行请求的数量,如以下片段所示:
.AsParallel()
.WithDegreeOfParallelism(15)
通过这种方式,您可以控制并行性,并且不会因为少量连接上的大量请求而使服务器过载。
关于客户端,您应该确保已将并发客户端连接的最大数量设置为适当的数量,以确保您的请求可以使用与服务器的单独连接,并防止重复使用可能导致"保持活动"问题的连接。如果使用连接的请求数超过了保持活动的最大连接数,或者超过了超时设置,则服务器可以关闭连接。
您可以使用ServicePointManager.DefaultConnectionLimit
设置以编程方式设置客户端连接限制。例如,您可以将其设置为50:
System.Net.ServicePointManager.DefaultConnectionLimit = 50;
下面是一个使用配置文件将最大连接数设置为50的示例:
<configuration>
<system.net>
<connectionManagement>
<add address="*" maxconnection="50" />
</connectionManagement>
</system.net>
我用"50"作为一个例子,你应该确定/计算/测量什么是你设置的最佳设置。
还要确保在每次请求后正确处理HTTP连接,以防止连接超时。