Может ли Linq AsParallel() избавиться от объектов SoapHttpClientProtocol преждевременно?

В веб-приложении ASP.Net MVC 4, над которым я работаю. У меня есть одна страница, которая в основном генерирует отчет, получая данные от службы 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 не является хорошим решением для того, что я пытаюсь сделать здесь?

Возможно ли, что другая проблема с потоками может вызвать ошибку, из-за которой мыльный клиент "сдается"?

Дополнительная информация

Этот конкретный прокси-сервер взаимодействует с ArcGIS Server. Как правило, вы можете проверить журналы сервера и посмотреть, когда конкретные запросы инициируются и если запросы не удалось. В этих журналах ничего не отображается.


Вот пример внутренней трассировки стека исключений, которую я получаю из кода AsParallel.

Исключение: System.AggregateException: произошла одна или несколько ошибок. ---> System.Net.WebException: лежащее в основе соединение было закрыто: соединение, которое, как ожидали, будет сохранено живым, было закрыто сервером. ---> System.IO.IOException: невозможно прочитать данные из транспортного соединения: существующее соединение было принудительно закрыто удаленным хостом. ---> System.Net.Sockets.SocketException: существующее соединение было принудительно закрыто удаленным узлом в System.Net.Sockets.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, Boolean probeRead) --- Конец внутренней трассировки стека исключений --- в System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(запрос веб-запроса) в System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(запрос веб-запроса) в System.Web.Services.Protocols.Inlient, Параметры Object[]) в ESRI.ArcGIS.SOAP.FeatureServerProxy.Query(Int32 LayerOrTableID, String DefinitionExpression, QueryFilter QueryFilter, ServiceDataOptions ServiceDataOptions, String GdbVersion, Double MaximumAllowableOffset) в System.Linq.Parallel.SelectQueryOperator 2.SelectQueryOperatorResults.GetElement(Int32 index) at System.Linq.Parallel.QueryResults 1.get_Item (индекс Int32) в System.Linq.Parallel.PartitionedDataSource 1.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.InnerInvoke() в System.Threading.Tasks.Task.Execute()

2 ответа

PLINQ даже не знает, что ваш объект соединения существует. Это не может закрыть это.

Внимательно прочитайте сообщение:

Существующее соединение было принудительно закрыто удаленным хостом.

Сервер неожиданно закрыл соединение. Ваш клиент не виноват.

Точная интерпретация исключения является важным навыком отладки. Эта информация была прямо в сообщении об исключении.

Возможно, вы создаете слишком большую нагрузку. Установите устойчивую степень параллелизма. Эвристика по умолчанию предназначена для работы процессора, а не для ввода-вывода.

.WithDegreeOfParallelism(10)

Соединение, которое, как ожидали, будет поддерживаться в живых, было закрыто сервером.

Это может означать, что сервер не поддерживает HTTP-поддержку.

Я не думаю, что вы делаете что-то ужасно неправильно AsParallel для ваших запросов HTTP Soap, и я не думаю, что это проблема многопоточности.

Однако параллельные запросы, очевидно, подталкивают ваш клиент / сервер к количеству ограничений на соединения, и именно поэтому вы видите, что соединения закрываются.

Я бы поспорил, что ваш клиент, сервер или оба не настроены для обработки количества одновременных соединений, которые вы устанавливаете. Вот почему это работает, когда вы запускаете запросы в последовательном режиме.

Я полагаю, у вас нет доступа к конфигурации сервера, поэтому вы могли бы контролировать количество параллельных запросов, которые вы одновременно отправляете на сервер, установив ParallelEnumerable.WithDegreeOfParallelism установка как в следующем фрагменте:

.AsParallel()
.WithDegreeOfParallelism(15)

Таким образом вы управляете параллелизмом и не рискуете перегружать сервер большим количеством запросов по небольшому количеству соединений.

Что касается клиента, вы должны убедиться, что вы установили макс. количество одновременных клиентских подключений к соответствующему номеру, просто чтобы убедиться, что ваши запросы могут использовать отдельные подключения к серверу, и предотвратить повторное использование подключений, которые могут вызвать проблемы Keep-Alive. Сервер может закрыть соединение, если число запросов, использующих соединение, превысило максимальное количество соединений для активности в реальном времени или если оно превышает настройки тайм-аута.

Вы можете установить лимит клиентского соединения программно, используя ServicePointManager.DefaultConnectionLimit установка. Например, вы можете установить его на 50:

System.Net.ServicePointManager.DefaultConnectionLimit = 50;

Вот пример настройки макс. Соединения до 50 с использованием файла конфигурации:

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

Я использовал "50" в качестве примера, вы должны определить / рассчитать / измерить, что является лучшим параметром для вашей установки.

Также убедитесь, что вы правильно утилизируете свои HTTP-соединения после каждого запроса, чтобы предотвратить тайм-ауты соединения.

Другие вопросы по тегам