#c# #multithreading #wcf-client
#c# #многопоточность #wcf-client
Вопрос:
У меня есть SOAP-клиент WCF, который я сгенерировал из service WSDL. Сервис предлагает, среди прочего, query
и batch
операции. Он также предполагает многопоточную обработку запросов.
При попытке распараллелить использование моего клиента я вижу странное поведение: клиент с радостью отправит столько query
запросов, сколько я скажу ему параллельно, но он будет отправлять только один batch
запрос за раз. Я использую Fiddler для просмотра трафика, и я вижу 10 открытых query
запросов, но batch
запросы всегда начинаются и заканчиваются по одному за раз.
Я использую Parallel.ForEach
для обоих путей кода MaxDegreeOfParallelism
значение 10. Я не меняюсь ServicePointManager.DefaultConnectionLimit
, хотя я заметил, что если я установлю для него значение меньше, чем количество потоков query
, запросы будут регулироваться. Я проверил, что TPL запускает несколько потоков, просмотрев ManagedThreadId
значение в параллельных путях выполнения.
Насколько я могу судить, единственное отличие с точки зрения клиента заключается в том, что query
использует метод HTTP GET
и batch
использует POST
метод. Вызовет ли это поведение, которое я вижу? Есть ли что-то еще, на что я могу посмотреть?
РЕДАКТИРОВАТЬ В соответствии с запросом, вот соответствующий код клиента (я удалил ServiceKnownType
атрибуты)
//generated client interface
//{...
[OperationContract(Action = "", ReplyAction = "*")]
[FaultContract(typeof (fault), Action = "", Name = "fault")]
[XmlSerializerFormat(SupportFaults = true)]
[return: MessageParameter(Name = "return")]
QueryResponse query(QueryRequest queryRequest);
[OperationContract(Action = "", ReplyAction = "*")]
[FaultContract(typeof (fault), Action = "", Name = "fault")]
[XmlSerializerFormat(SupportFaults = true)]
[return: MessageParameter(Name = "return")]
BatchResponse batch(BatchRequest batchRequest);
//...}
//generated client class
//{...
public QueryResponse query(QueryRequest queryRequest)
{
return this.Channel.query(queryRequest);
}
public BatchResponse batch(BatchRequest batchRequest)
{
return this.Channel.batch(batchRequest);
}
//...}
ПРАВКА2
Вот мой вывод отладки, пытаюсь отследить это.
Creating...{Thread Id}
записывается на консоль непосредственно перед тем, как я начну собирать полезную нагрузку дляbatch
операции
Sending...{Thread Id}
строки записываются в консоль непосредственно передbatch
вызовом операции
Sent...{Thread Id}
строки записываются в консоль сразу после завершенияbatch
операции
1:53:58 PM (Thread 4)
1:53:58 PM (Thread 19)
1:53:58 PM (Thread 20)
1:53:58 PM (Thread 16)
1:53:58 PM (Thread 18)
1:53:58 PM (Thread 17)
1:53:58 PM (Thread 7)
1:53:58 PM (Thread 15)
Creating...19
Creating...15
Creating...16
Creating...17
Creating...7
Creating...4
Creating...20
Creating...18
Sending...17
Sending...7
Sending...20
Sending...19
Sending...16
Sending...18
Sending...4
Sending...15
1:53:59 PM (Thread 22)
Creating...22
Sending...22
1:53:59 PM (Thread 23)
Creating...23
Sending...23
Sent...17
Sent...15
Sent...7
Sent...18
Sent...20
Sent...16
Sent...4
Sent...19
Sent...22
Sent...23
И вот журнал скрипача для этого запуска:
Для справки, вот фрагмент из журнала скрипача для query
пути к коду:
Комментарии:
1. Вы контролируете службу? Служба может быть настроена на обработку только одного вызова за раз. См. Главу 8 в книге Juval «Программирование служб WCF».
2. @EricScherrer Нет — услуга предоставляется третьей стороной. Даже если бы служба регулировала, я все равно ожидал бы увидеть запросы на подключение, ожидающие в Fiddler, если клиент выполнял несколько одновременных запросов.
3. Можете ли вы опубликовать созданный клиент? Интересно, есть ли какие-либо интересные атрибуты в этом методе.
4. @EricScherrer Я обновил вопрос этим кодом. В методах класса нет атрибутов, но я включил все, кроме
ServiceKnownType
атрибутов в методах интерфейса.5. Я не уверен, что на самом деле нет никакой разницы в том, как вы обрабатываете эти два метода. Попробуйте создать минимальный фрагмент кода, чтобы воспроизвести это. Просто вызовите Parallel . ForEach с выдуманной рабочей нагрузкой и однострочным телом, вызывающим службу. Опубликуйте код здесь.