threading thread programming parallel net examples c# .net multithreading logging parallel-processing

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:

  1. Sí, bloquea hasta que vuelva la ejecución del elemento más lento.
  2. 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 ... } });