8

¿Qué sucede si necesita ejecutar varias tareas de E/S asíncronas en paralelo pero necesita asegurarse de que no se ejecutan más de X procesos de E/S al mismo tiempo; y las tareas de procesamiento pre y post de E/S no deberían tener tal limitación.¿Cómo se ejecutan correctamente varias tareas asíncronas en paralelo?

Aquí hay un escenario: digamos que hay 1000 tareas; cada uno de ellos acepta una cadena de texto como parámetro de entrada; transforma ese texto (procesamiento previo de E/S) y luego escribe ese texto transformado en un archivo. El objetivo es hacer que la lógica de preprocesamiento utilice el 100% de CPU/Núcleos y la parte de E/S de las tareas se ejecutan con un máximo de 10 grados de paralelismo (10 como máximo se abren simultáneamente para escribir archivos a la vez).

¿Puede proporcionar un código de muestra de cómo hacerlo con C#/.NET 4.5?

http://blogs.msdn.com/b/csharpfaq/archive/2012/01/23/using-async-for-file-access-alan-berman.aspx

+0

Rx 2.0 podría ser una buena opción para esto (estrangulamiento de la segunda etapa a 10 a la vez), pero no estoy lo suficientemente familiarizado con eso para decirlo con seguridad. : -/ –

Respuesta

7

Creo que usar TPL Dataflow para esto sería una buena idea: crear bloques de pre y post proceso con paralelismo ilimitado, un bloque de escritura de archivos con paralelismo limitado y vincularlos entre sí. Algo así como:

var unboundedParallelismOptions = 
    new ExecutionDataflowBlockOptions 
    { 
     MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded 
    }; 

var preProcessBlock = new TransformBlock<string, string>(
    s => PreProcess(s), unboundedParallelismOptions); 

var writeToFileBlock = new TransformBlock<string, string>(
    async s => 
      { 
       await WriteToFile(s); 
       return s; 
      }, 
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 }); 

var postProcessBlock = new ActionBlock<string>(
    s => PostProcess(s), unboundedParallelismOptions); 

var propagateCompletionOptions = 
    new DataflowLinkOptions { PropagateCompletion = true }; 

preProcessBlock.LinkTo(writeToFileBlock, propagateCompletionOptions); 
writeToFileBlock.LinkTo(postProcessBlock, propagateCompletionOptions); 

// use something like await preProcessBlock.SendAsync("text") here 

preProcessBlock.Complete(); 
await postProcessBlock.Completion; 

Dónde WriteToFile() podría tener este aspecto:

private static async Task WriteToFile(string s) 
{ 
    using (var writer = new StreamWriter(GetFileName())) 
     await writer.WriteAsync(s); 
} 
+0

+1 Eso es interesante ... ¡gracias! –

+0

¿Qué son los métodos 'PreProcess' y' PostProcess' aquí? – shashwat

+0

@shashwat Hacen lo que sea necesario. La pregunta original habla de "tareas de procesamiento de E/S pre y post", así que representé eso usando métodos. – svick

1

suena como te gustaría considerar un Djikstra semáforo para controlar el acceso a la puesta en marcha de las tareas.

Sin embargo, esto suena como un típico problema de cola/número fijo de consumidores, que puede ser una forma más apropiada de estructurarlo.

Cuestiones relacionadas