Estoy ejecutando un bucle Parallel.For en un poco más de 7500 objetos. Dentro de ese ciclo, estoy haciendo una serie de cosas para cada uno de esos objetos, específicamente llamando a dos servicios web y dos métodos internos. Los servicios web simplemente inspeccionan el objeto, procesan y devuelven una cadena que luego configuro como una propiedad en el objeto. Lo mismo ocurre con los dos métodos internos.Paralelo.Para congelar después de alrededor de 1370 iteraciones, no tengo idea de por qué
No escribo nada en el disco ni leo desde el disco.
También actualizo la interfaz de usuario en una aplicación de winforms con una etiqueta y una barra de progreso para que el usuario sepa dónde está. Aquí está el código:
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);
Esto se lleva a cabo en una máquina Win7 de 32 bits.
¿Alguna idea de por qué esto se congela de repente cuando el incremento está alrededor de 1370 o más (han sido 1361, 1365 y 1371)?
¿Alguna idea sobre cómo puedo depurar esto y ver qué se bloquea si hay algo?
EDIT:
Algunas respuestas a los siguientes comentarios:
@BrokenGlass - No, no de interoperabilidad. Probaré la compilación x86 y te lo haré saber.
@chibacity - Debido a que está en una tarea de segundo plano, no congela la interfaz de usuario. Hasta el momento en que se congela, la barra de progreso y la etiqueta marcan aproximadamente 2 por segundo. Cuando se congela, simplemente deja de moverse. Puedo verificar que el número al que se detiene se haya procesado, pero no más. El uso de CPU en un núcleo dual 2.2GHz es mínimo durante la operación en 3-4% cada uno y 1-2% una vez que se congela.
@Henk Holterman - Tarda alrededor de 10-12 minutos para llegar a 1360 y sí, puedo verificar que todos esos registros se hayan procesado pero no los registros restantes.
@CodeInChaos - ¡Gracias, intentaré eso! El código funciona si elimino el paralelo, solo lleva una eternidad y un día. No he intentado restringir el número de subprocesos, pero lo haré.
EDIT 2:
Algunos detalles en cuanto a lo que está pasando con los servicios web
Básicamente lo que está pasando con los servicios web es que pasan en algunos datos y recibir datos (un XmlNode). Ese nodo se utiliza luego en el proceso Conversión1 que a su vez establece otra propiedad en la entidad que se envía al método CallSvc2, y así sucesivamente. Se ve así:
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);
}
Como puede ver, es bastante sencillo. Están sucediendo muchas cosas en algunos de los métodos de conversión, pero ninguno debería estar bloqueando. Y como se indica a continuación, hay 1024 subprocesos en estado de "espera" que están todos sentados en las llamadas al servicio web. Leí aquí http://www.albahari.com/threading/ que el MaxThreads está predeterminado en 1023 para .Net 4 en la máquina de 32 bits.
¿Cómo puedo liberar esos hilos de espera dado lo que tengo aquí?
Tuve un problema similar antes: intentaría construir el proyecto en modo x86 para ver si eso cambia algo. ¿No harías InterOp en tus tareas? – BrokenGlass
Se está congelando o simplemente va muy lento. ¿Cómo es el uso de la CPU? –
Aún no trabajé con TPL, pero ¿no puede simplemente interrumpir el depurador y verificar qué método, llamar a las funciones detenidas? ¿Funciona el código si lo reemplaza con un ciclo for normal? ¿Y qué sucede si usa 'Parallel.For' pero lo restringe a uno o dos hilos? – CodesInChaos