2012-07-31 11 views
6

He siguiente código:Java procesamiento de archivos paralelo

import java.io.*; 
import java.util.concurrent.* ; 
public class Example{ 
public static void main(String args[]) { 
    try { 
     FileOutputStream fos = new FileOutputStream("1.dat"); 
     DataOutputStream dos = new DataOutputStream(fos); 

     for (int i = 0; i < 200000; i++) { 
      dos.writeInt(i); 
     } 
     dos.close();               // Two sample files created 

     FileOutputStream fos1 = new FileOutputStream("2.dat"); 
     DataOutputStream dos1 = new DataOutputStream(fos1); 

     for (int i = 200000; i < 400000; i++) { 
      dos1.writeInt(i); 
     } 
     dos1.close(); 

     Exampless.createArray(200000); //Create a shared array 
     Exampless ex1 = new Exampless("1.dat"); 
     Exampless ex2 = new Exampless("2.dat"); 
     ExecutorService executor = Executors.newFixedThreadPool(2); //Exexuted parallaly to cont number of matches in two file 
     long startTime = System.nanoTime(); 
     long endTime; 
     Future<Integer> future1 = executor.submit(ex1); 
     Future<Integer> future2 = executor.submit(ex2); 
     int count1 = future1.get(); 
     int count2 = future2.get(); 
     endTime = System.nanoTime(); 
     long duration = endTime - startTime; 
     System.out.println("duration with threads:"+duration); 
     executor.shutdown(); 
     System.out.println("Matches: " + (count1 + count2)); 

     startTime = System.nanoTime(); 
     ex1.call(); 
     ex2.call(); 
     endTime = System.nanoTime(); 
     duration = endTime - startTime; 
     System.out.println("duration without threads:"+duration); 

    } catch (Exception e) { 
     System.err.println("Error: " + e.getMessage()); 
    } 
} 
} 

class Exampless implements Callable { 

public static int[] arr = new int[20000]; 
public String _name; 

public Exampless(String name) { 
    this._name = name; 
} 

static void createArray(int z) { 
    for (int i = z; i < z + 20000; i++) { //shared array 
     arr[i - z] = i; 
    } 
} 

public Object call() { 
    try { 
     int cnt = 0; 
     FileInputStream fin = new FileInputStream(_name); 
     DataInputStream din = new DataInputStream(fin);  // read file and calculate number of matches 
     for (int i = 0; i < 20000; i++) { 
      int c = din.readInt(); 
      if (c == arr[i]) { 
       cnt++; 
      } 
     } 
     return cnt ; 
    } catch (Exception e) { 
     System.err.println("Error: " + e.getMessage()); 
    } 
    return -1 ; 
} 

} 

Dónde estoy tratando de contar el número de partidos en una matriz con dos archivos. Ahora, aunque lo estoy ejecutando en dos subprocesos, el código no funciona bien porque:

(ejecutándolo en subproceso único, archivo 1 + archivo 2 tiempo de lectura) < (archivo 1 || archivo 2 tiempo de lectura en subproceso múltiple)

¿Alguien me puede ayudar a resolver esto? (Tengo 2 núcleos de CPU y el tamaño del archivo es de aproximadamente 1.5 GB).

+0

@SurajChandran, la mayoría de las veces. Y realmente no tiene efecto :) Simplemente haz una prueba. – Arpssss

+0

Los archivos no son de 1.5GB, solo son ~ 80K. –

+0

@KeithRandall, acabo de dar uso de muestra. – Arpssss

Respuesta

7

En el primer caso está leyendo secuencialmente un archivo, byte por byte, bloque por bloque. Esto es tan rápido como puede ser E/S de disco, siempre que el archivo no esté muy fragmentado. Cuando haya terminado con el primer archivo, el disco/sistema operativo encuentra el comienzo del segundo archivo y continúa leyendo el disco de manera muy eficiente y lineal.

En el segundo caso, cambia constantemente entre el primer archivo y el segundo, forzando al disco a buscar de un lugar a otro. Este tiempo extra de búsqueda (aproximadamente 10 ms) es la raíz de su confusión.

Ah, y usted sabe que el acceso al disco es de un solo subproceso y su tarea es E/S enlazada, por lo que no hay forma de dividir esta tarea en varios subprocesos, siempre y cuando lea desde el mismo disco físico. Su enfoque sólo podría justificarse si:

  • cada hilo, excepto la lectura de un archivo, también fue la realización de algún CPU o las operaciones más lentas, por el bloqueo de un orden de magnitud en comparación con E/S.

  • archivos están en diferentes unidades físicas (partición diferente no es suficiente) o en algunas configuraciones RAID

  • está utilizando unidad SSD

+1

+1. Este es un problema fundamental que muchas personas no entienden: solo aumentar el reactivo limitante aumentará el rendimiento. – RedGreasel

1

Usted no recibirá ningún beneficio de multihilo como Tomasz señaló al leer los datos del disco. Puede obtener una mejora en la velocidad si multiplique las comprobaciones, es decir, si carga los datos de los archivos en matrices secuencialmente y luego los hilos ejecutan la comprobación en paralelo. Pero teniendo en cuenta el pequeño tamaño de tus archivos (~ 80kb) y el hecho de que solo estás comparando ints, dudo que la mejora en el rendimiento valga la pena.

Algo que definitivamente mejorará tu velocidad de ejecución si no usas readInt(). Como sabe que está comparando 20000 ints, debe leer todas las 20000 entradas en una matriz al mismo tiempo para cada archivo (o al menos en bloques), en lugar de llamar a la función readInt() 20000 veces.

Cuestiones relacionadas