2010-02-15 24 views
13

Estoy interesado en aprender sobre programación paralela en C# .NET (no como todo lo que hay que saber, pero los conceptos básicos y tal vez algunas buenas prácticas), por lo tanto, he decidido reprogramar un programa anterior mío que se llama ImageSyncer. ImageSyncer es un programa realmente simple, lo único que hace es escanear a través de una carpeta y encontrar todos los archivos que terminan en .jpg, luego calcula la nueva posición de los archivos según la fecha en que fueron tomadas (análisis de xif-data o lo que sea se llama). Después de que se haya generado una ubicación, el programa verifica si hay archivos existentes en esa ubicación, y si existe, mira el último tiempo de escritura del archivo para copiar y el archivo "en su camino". Si son iguales, el archivo se salta. Si no se crea una suma de control md5 de ambos archivos, se hace coincidir. Si no hay coincidencia, el archivo que se va a copiar recibe una nueva ubicación para copiarse (por ejemplo, si se va a copiar a "C: \ test.jpg" se copia a "C: \ test (1). jpg "en su lugar). El resultado de esta operación se rellena en una cola de un tipo de estructura que contiene dos cadenas, el archivo original y la posición para copiarlo. Luego, esa cola se repite hasta que esté vacía y los archivos se copien.Programación paralela en C#

En otras palabras, hay 4 operaciones:

1. Scan directory for jpegs 
2. Parse files for xif and generate copy-location 
3. Check for file existence and if needed generate new path 
4. Copy files 

Y por eso quiero volver a escribir este programa para que sea paralelo y ser capaz de realizar varias de las operaciones al mismo tiempo, y me preguntaba lo la mejor manera de lograr eso sería. He encontrado dos modelos diferentes en los que puedo pensar, pero ninguno de ellos podría ser bueno en absoluto. El primero es paralizar los 4 pasos del programa anterior, de modo que cuando se ejecuta el primer paso, se realiza en varios hilos, y cuando finaliza todo el paso 1, se inicia el paso 2. El otro (que me parece más interesante porque no tengo idea de cómo hacerlo) es crear una especie de modelo de trabajador y consumidor, de modo que cuando un hilo termina con el paso 1, otro toma el control y realiza el paso 2 en ese momento. objeto (o algo así). Pero como dije, no sé si alguna de estas son buenas soluciones. Además, no sé mucho sobre programación paralela en absoluto. Sé cómo hacer un hilo, y cómo hacer que realice una función teniendo en cuenta un objeto como su único parámetro, y también he usado la clase BackgroundWorker en una ocasión, pero no estoy tan familiarizado con ninguno de ellos. .

Cualquier entrada sería apreciada.

+9

Esto suena como una tarea interesante, pero ya que es probable que sea IO Es probable que múltiples hilos encuadernados en el disco hagan que el programa se ejecute _slower_ que si solo usara un hilo. –

+0

Gracias, realmente no consideré esto. Pero creo que al menos los pasos 2 y 3 podrían beneficiarse del uso de varios hilos, ¿no le parece? – Alxandr

+0

http://messagingbus.codeplex.com/ puede ayudar –

Respuesta

2

Esta es la referencia que utilizo para C# hilo: http://www.albahari.com/threading/

Como solo PDF: http://www.albahari.com/threading/threading.pdf

Para su segundo enfoque:

he trabajado en algunas aplicaciones multiproceso productor/consumidor, donde cada tarea es un código que los bucles de fo r alguna vezUn "inicializador" externo inicia un hilo separado para cada tarea e inicializa un EventWaitHandle para cada tarea. Para cada tarea hay una cola global que se puede usar para producir/consumir entradas.

En su caso, su programa externo agregará cada directorio a la cola para Tarea1, y establecerá el Manejador de tareas de evento para Tarea1. La tarea 1 se "activaría" desde su EventWaitHandler, obtendrá el recuento de directorios en su cola y, luego, mientras el recuento es mayor que 0, obtenga el directorio de la cola, escanee todos los archivos .jpgs y agregue cada ubicación .jpg a una segunda cola, y configure el EventWaitHandle para la tarea 2. La tarea 2 lee su entrada, lo procesa, lo remite a la cola para la Tarea 3 ...

Puede ser un poco doloroso obtener todo el bloqueo para funciona bien (básicamente bloqueo cualquier acceso a la cola, incluso algo tan simple como obtener su cuenta). Se supone que .NET 4.0 tiene estructuras de datos que admitirán automáticamente una cola de productor/consumidor sin bloqueos.

1

Problema interesante. Se me ocurrieron dos enfoques. El primero se basa en PLinq y el segundo se basa en te Rx Framework.

El primero itera a través de los archivos en paralelo. El segundo genera de manera asincrónica los archivos del directorio.

Así es como se ve en una versión mucho más simplificada (El primer método requiere .Net 4.0, ya que utiliza PLINQ)

string direcory = "Mydirectory"; 
    var jpegFiles = System.IO.Directory.EnumerateFiles(direcory,"*.jpg"); 


    // -- PLinq -------------------------------------------- 
    jpegFiles 
    .AsParallel() 
    .Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) }) 
    .Do(fileInfo => 
     { 
      if (!File.Exists(fileInfo.NewLocation) || 
       (File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation))) 
       File.Copy(fileInfo.OldLocation,fileInfo.NewLocation); 
     }) 
    .Run(); 

    // ----------------------------------------------------- 


    //-- Rx Framework --------------------------------------------- 
    var resetEvent = new AutoResetEvent(false); 
    var doTheWork = 
    jpegFiles.ToObservable() 
    .Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) }) 
    .Subscribe(fileInfo => 
     { 
      if (!File.Exists(fileInfo.NewLocation) || 
       (File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation))) 
      File.Copy(fileInfo.OldLocation,fileInfo.NewLocation); 
     },() => resetEvent.Set()); 

    resetEvent.WaitOne(); 
    doTheWork.Dispose(); 

    // ----------------------------------------------------- 
+0

PLinq requiere .net 4.0, ¿no es correcto? – Alxandr

+0

Sí, requiere .Net 4.0 –

+0

+1 para mencionar y proporcionar un ejemplo para el enfoque "Rx". –