c# - thread - ¿Parallel.ForEach Block?
thread programming c# (2)
El número 1 es correcto; Parallel.ForEach
no regresa hasta que el ciclo se haya completado. Si no quiere ese comportamiento, simplemente puede ejecutar su bucle como una Task
y ejecutarlo en otro hilo.
¿La función .net Parallel.ForEach bloquea el hilo de llamada? Mi conjetura sobre el comportamiento es uno de estos:
- Sí, bloquea hasta que vuelva la ejecución del elemento más lento.
- No, no bloquea y devuelve el control de inmediato. Los elementos para ejecutar en paralelo se realizan en hilos de fondo.
O tal vez está sucediendo algo más, ¿alguien lo sabe con certeza?
Esta pregunta surgió al implementar esto en una clase de registro:
public class MultipleLoggingService : LoggingServiceBase
{
private readonly List<LoggingServiceBase> loggingServices;
public MultipleLoggingService(List<LoggingServiceBase> loggingServices)
{
this.loggingServices = loggingServices;
LogLevelChanged += OnLogLevelChanged;
}
private void OnLogLevelChanged(object sender, LogLevelChangedArgs args)
{
loggingServices.ForEach(l => l.LogLevel = LogLevel);
}
public override LogMessageResponse LogMessage(LogMessageRequest request)
{
if (request.LogMessage)
Parallel.ForEach(loggingServices, l => l.LogMessage(request));
return new LogMessageResponse{MessageLogged = request.LogMessage};
}
}
Observe que el método LogMessage
llama a otros servicios de registro. Necesito que esa parte vuelva de inmediato, por lo que no bloquea el hilo de llamada.
Actualización: Basado en comentarios de otros (confirmamos que el comportamiento es # 1). Así que he tomado consejos para usar la biblioteca de Task y reescribí el ciclo de esta manera:
if (request.LogMessage)
foreach (var loggingService in loggingServices)
Task.Factory.StartNew(() => loggingService.LogMessage(request));
Re su actualización, StartNew en un foreach normal ():
Esto puede no ser el más óptimo para colecciones grandes, y no obtiene un punto para manejar errores.
Sus servicios de registro probablemente no contengan miles de elementos, pero el manejo de errores sigue siendo un punto.
Considerar:
Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(loggingServices, l => l.LogMessage(request));
}
catch(SomeException ex)
{
// at least try to log it ...
}
});