2012-08-08 18 views
21

Tengo un archivo grande que tarda varias horas en procesarse. Así que estoy pensando en tratar de estimar los trozos y leer los trozos en paralelo. ¿es posible leer simultáneamente en un solo archivo? He examinado tanto RandomAccessFile como nio.FileChannel, pero en base a otras publicaciones no estoy seguro de si este enfoque funcionaría. sugerencia !!Lectura simultánea de un archivo (prefijado en java)

+0

¿Qué sistema operativo? Java o no, Windows no maneja bien este tipo de cosas – SJuan76

+0

Leí en alguna parte que cuando se trata de diskIO, es posible que no obtenga la ventaja de la concurrencia. – kosa

+2

¿Por qué el voto a favor? Encontré esta pregunta muy interesante. – hectorg87

Respuesta

1

Si está leyendo un archivo de un disco duro, la forma más rápida de obtener los datos es leer el archivo de principio a fin, es decir, no concurrentemente.

Ahora bien, si el proceso lleva tiempo, puede ser beneficioso que varios subprocesos procesen diferentes fragmentos de datos al mismo tiempo, pero eso no tiene nada que ver con la lectura del archivo.

+1

Creo que esto no responde la pregunta. La pregunta es: ¿es posible "paralelizar" la lectura de un archivo grande? – hectorg87

+0

Tenía la impresión de que la pregunta fundamental estaba más en el paradero de "¿puedo leer un archivo más rápido paralelizando la lectura?" – Buhb

+1

Después de su edición: supongo que tiene que ver con la lectura porque es un "archivo grande" como él dijo. Por cierto, el -1 no es de mí – hectorg87

7

Puede paralelizar la lectura de un archivo grande siempre que tenga múltiples ejes independientes. P.ej. si tiene un sistema de archivos eliminados Raid 0 + 1, puede ver una mejora en el rendimiento al activar múltiples lecturas simultáneas en el mismo archivo.

Sin embargo, si tiene un sistema de archivos combinado como Raid 5 o 6 o un simple disco simple. Es muy probable que la lectura secuencial del archivo sea la manera más rápida de leer desde ese disco. Nota: el sistema operativo es lo suficientemente inteligente como para recuperar las lecturas cuando ve que está leyendo de forma secuencial, por lo que no es probable que sea útil utilizar un hilo adicional para hacerlo.

es decir, el uso de varios hilos no hará que el disco sea más rápido.

Si desea leer más rápido en el disco, use una unidad más rápida. Un HDD SATA típico puede leer aproximadamente 60 MB/segundo y realizar 120 IOPS. Una unidad SSD SATA típica puede leer a aproximadamente 400 MB/sy realizar 80,000 IOPS y una SSD PCI típica puede leer a 900 MB/sy realizar 230,000 IOPS.

+0

Peter, el problema es con un solo archivo en mi disco duro. Para RAID, etc., ¿cómo puedo dividir el archivo? – user1132593

+0

RAID dividirá el archivo automáticamente si usa striping (o RAID 1 lo copiará en dos discos) RAID 5 y 6 pueden obtener el beneficio de pelar, pero esto depende de su controlador ya que a menudo se optimizan para un rendimiento máximo, es decir, lecturas secuenciales . –

+1

Estoy ejecutando una prueba para el mismo caso de uso, leyendo un solo archivo de múltiples hilos. Descubrí que tener varios subprocesos mejora el rendimiento si el almacenamiento subyacente es una unidad de disco SATA y mejora el rendimiento si es un disco SAS. ¿Sería debido a la tecnología punto a punto utilizada en SAS o mi prueba está haciendo algo incorrecto? –

1

Puede procesar en paralelo, sin embargo, su disco duro solo puede leer una pieza de datos a la vez. Si lee en el archivo con un solo hilo, puede procesar los datos con varios hilos.

15

La pregunta más importante aquí es ¿cuál es el cuello de botella en su caso.

Si el cuello de botella es su disco IO, entonces no hay mucho que pueda hacer en la parte del software. Paralelizar el cálculo solo empeorará las cosas, porque leer el archivo de diferentes partes simultáneamente degradará el rendimiento del disco.

Si el cuello de botella es potencia de procesamiento, y tiene múltiples núcleos de CPU, puede aprovechar la ventaja de iniciar varios subprocesos para trabajar en diferentes partes del archivo. Puede crear con seguridad varios InputStream o Reader para leer diferentes partes del archivo en paralelo (siempre que no supere el límite de su sistema operativo para la cantidad de archivos abiertos). Puede separar el trabajo en tareas y ejecutarlas en paralelo, como en este ejemplo:

import java.io.*; 
import java.util.*; 
import java.util.concurrent.*; 

public class Split { 
    private File file; 

    public Split(File file) { 
     this.file = file; 
    } 

    // Processes the given portion of the file. 
    // Called simultaneously from several threads. 
    // Use your custom return type as needed, I used String just to give an example. 
    public String processPart(long start, long end) 
     throws Exception 
    { 
     InputStream is = new FileInputStream(file); 
     is.skip(start); 
     // do a computation using the input stream, 
     // checking that we don't read more than (end-start) bytes 
     System.out.println("Computing the part from " + start + " to " + end); 
     Thread.sleep(1000); 
     System.out.println("Finished the part from " + start + " to " + end); 

     is.close(); 
     return "Some result"; 
    } 

    // Creates a task that will process the given portion of the file, 
    // when executed. 
    public Callable<String> processPartTask(final long start, final long end) { 
     return new Callable<String>() { 
      public String call() 
       throws Exception 
      { 
       return processPart(start, end); 
      } 
     }; 
    } 

    // Splits the computation into chunks of the given size, 
    // creates appropriate tasks and runs them using a 
    // given number of threads. 
    public void processAll(int noOfThreads, int chunkSize) 
     throws Exception 
    { 
     int count = (int)((file.length() + chunkSize - 1)/chunkSize); 
     java.util.List<Callable<String>> tasks = new ArrayList<Callable<String>>(count); 
     for(int i = 0; i < count; i++) 
      tasks.add(processPartTask(i * chunkSize, Math.min(file.length(), (i+1) * chunkSize))); 
     ExecutorService es = Executors.newFixedThreadPool(noOfThreads); 

     java.util.List<Future<String>> results = es.invokeAll(tasks); 
     es.shutdown(); 

     // use the results for something 
     for(Future<String> result : results) 
      System.out.println(result.get()); 
    } 

    public static void main(String argv[]) 
     throws Exception 
    { 
     Split s = new Split(new File(argv[0])); 
     s.processAll(8, 1000); 
    } 
} 
+0

gracias Petr, tengo algo similar, pero estaba usando Runnables (antiguo modo). Mi observación fue que solo un hilo estaba ocupado y por eso publiqué esta pregunta. Volveré a intentarlo pronto y publicaré mis observaciones – user1132593

+2

Pude cortar el archivo y leerlo al mismo tiempo. Para .Archivo de texto de 5GB aquí fueron mis resultados (hh.mm.ss.SSS): trozos = [1]: 0: 18: 10.328 trozos = [2]: 0: 13: 19.125 trozos = [3]: 0: 12: 54.824 . No es una gran diferencia. Sin embargo, para mí, la mejor solución fue comprimir el archivo y procesar en serie el archivo zip. Esto fue debido a la alta relación de compresión. El archivo comprimido terminó siendo 10 MB – user1132593

Cuestiones relacionadas