Я запускаю цикл Parallel.For для немногим более 7500 объектов. Внутри этого цикла for я выполняю ряд действий с каждым из этих объектов, в частности вызываю две веб-службы и два внутренних метода. Веб-службы просто проверяют объект, обрабатывают и возвращают строку, которую я затем устанавливаю как свойство объекта. То же самое и с двумя внутренними методами.
Я ничего не записываю на диск и не читаю с диска.
Я также обновляю пользовательский интерфейс в приложении winforms, добавляя метку и индикатор выполнения, чтобы пользователь знал, где это в. Вот код:
var task = Task.Factory.StartNew(() =>
{
Parallel.For(0, upperLimit, (i, loopState) =>
{
if (cancellationToken.IsCancellationRequested)
loopState.Stop();
lblProgressBar.Invoke(
(Action)
(() => lblProgressBar.Text = string.Format("Processing record {0} of {1}.", (progressCounter++), upperLimit)));
progByStep.Invoke(
(Action)
(() => progByStep.Value = (progressCounter - 1)));
CallSvc1(entity[i]);
Conversion1(entity[i]);
CallSvc2(entity[i]);
Conversion2(entity[i]);
});
}, cancellationToken);
Это происходит на 32-битной машине Win7.
Есть идеи относительно того, почему это внезапно зависает, когда инкремент около 1370 или около того (это было 1361, 1365 и 1371)?
Любые идеи относительно того, как я могу отладить это и посмотреть, что блокируется?
EDIT:
Некоторые ответы на комментарии ниже:
@BrokenGlass - Нет, без взаимодействия. Я попробую компиляцию x86 и дам вам знать.
@chibacity - Поскольку это фоновая задача, пользовательский интерфейс не замораживается. До тех пор, пока он не зависнет, индикатор выполнения и метка будут двигаться примерно 2 раза в секунду. Когда он замерзает, он просто перестает двигаться. Я могу проверить, обработан ли номер, на котором он останавливается, но не более того. Использование ЦП на двухъядерном процессоре 2,2 ГГц минимально во время работы - 3-4% каждое и 1-2% после зависания.
@Henk Holterman - Чтобы добраться до 1360, требуется около 10-12 минут, и да, я может проверить, что все эти записи были обработаны, но не оставшиеся записи.
@CodeInChaos - Спасибо, я попробую! Код действительно работает, если я уберу параллель, это займет целую вечность и день. Я не пробовал ограничивать количество потоков, но буду.
РЕДАКТИРОВАТЬ 2:
Некоторые подробности относительно того, что происходит с веб-сервисами.
В основном, что происходит с веб-сервисами, это то, что они передают некоторые данные и получают данные (XmlNode). Затем этот узел используется в процессе Conversion1, который, в свою очередь, устанавливает другое свойство объекта, которое отправляется методу CallSvc2, и так далее. Это выглядит так:
private void CallSvc1(Entity entity)
{
var svc = new MyWebService();
var node = svc.CallMethod(entity.SomeProperty);
entity.FieldToUpdate1.LoadXml(node.InnerXml);
}
private void Conversion1(Entity entity)
{
// Do some xml inspection/conversion stuff
if (entity.FieldToUpdate1.SelectSingleNode("SomeNode") == "something") {
entity.FieldToUpdate2 = SomethingThatWasConverted;
}
else {
// Do some more logic
}
}
private void CallSvc2(Entity entity)
{
var svc = new SomeOtherWebService();
var xmlNode = svc.MethodToCall(entity.FieldToUpdate2.InnerXml);
entity.AnotherXmlDocument.LoadXml(xmlNode.InnerXml);
}
Как видите, это довольно простой материал. В некоторых методах преобразования много чего происходит, но ни один из них не должен блокировать. И, как указано ниже, 1024 потока находятся в состоянии «ожидания», которые все сидят на вызовах веб-службы. Я прочитал здесь http://www.albahari.com/threading/ , что для MaxThreads по умолчанию установлено значение 1023 для .Net 4 на 32-битной машине.
Как я могу освободить эти ожидающие потоки, учитывая то, что у меня есть?