2012-08-08 25 views
21

Ho un file di grandi dimensioni che richiede più ore per l'elaborazione. Quindi sto pensando di provare a stimare i pezzi e leggere i blocchi in parallelo. è possibile leggere simultaneamente su un singolo file? Ho esaminato sia RandomAccessFile che nio.FileChannel ma sulla base di altri post non sono sicuro che questo approccio funzionerebbe. suggerimento !!Lettura simultanea di un file (java preffered)

+0

Quale sistema operativo? Java o no, Windows non gestisce bene questo tipo di cose – SJuan76

+0

Ho letto da qualche parte che quando è diskIO, non si può trarre vantaggio dalla concorrenza. – kosa

+2

Perché il downvote? Ho trovato questa domanda molto interessante. – hectorg87

risposta

1

Se stai leggendo un file da un disco rigido, il modo più veloce per ottenere i dati è quello di leggere il file dall'inizio alla fine, cioè non contemporaneamente.

Ora, se l'elaborazione richiede tempo, potrebbe trarre vantaggio dall'avere diversi thread che elaborano diversi blocchi di dati contemporaneamente, ma ciò non ha nulla a che fare con il modo in cui si sta leggendo il file.

+1

Penso che questo non risponda alla domanda. La domanda è: è possibile "parallelizzare" la lettura di un file di grandi dimensioni? – hectorg87

+0

Avevo l'impressione che la questione fondamentale fosse più nel luogo in cui "posso leggere un file più velocemente parallelizzando la lettura?" – Buhb

+1

Dopo la modifica: immagino che abbia a che fare con la lettura perché è un "file di grandi dimensioni" come ha affermato. btw, il -1 non è da me – hectorg87

7

È possibile parallelizzare la lettura di un file di grandi dimensioni purché si dispongano più spindali indipendenti. Per esempio. se si dispone di un file system Raid 0 + 1 stripped, è possibile vedere un miglioramento delle prestazioni attivando più letture contemporanee sullo stesso file.

Se tuttavia si dispone di un file system combinato come Raid 5 o 6 o un disco singolo semplice. È molto probabile che la lettura sequenziale del file sia il modo più veloce per leggere da quel disco. Nota: il sistema operativo è abbastanza intelligente da precaricare le letture quando vede che stai leggendo in modo sequenziale, quindi è improbabile che l'utilizzo di un thread aggiuntivo per farlo non sia di aiuto.

Ad esempio, l'utilizzo di più thread non renderà il disco più veloce.

Se si desidera leggere più velocemente dal disco, utilizzare un'unità più veloce. Un tipico HDD SATA può leggere circa 60 MB/secondo ed eseguire 120 IOPS. Una tipica unità SSD SATA può leggere a circa 400 MB/se eseguire 80.000 IOPS e un tipico SSD PCI può leggere a 900 MB/se eseguire 230.000 IOPS.

+0

Peter, Il problema è con un singolo file sul mio disco fisso. Per RAID ecc. Come dividerei il file? – user1132593

+0

RAID dividerà automaticamente il file se utilizzi lo striping (o RAID 1 lo copierà su due dischi) I RAID 5 e 6 possono ottenere il vantaggio dello stripping ma questo dipende dal controller in quanto questi sono spesso ottimizzati per il massimo throughput cioè letture sequenziali . –

+1

Sto eseguendo un test per lo stesso caso d'uso: la lettura di un singolo file da più thread. Ho scoperto che avere più thread migliora le prestazioni se lo storage sottostante è un'unità disco SATA mentre migliora le prestazioni se è un'unità SAS. Sarebbe a causa della tecnologia point-to-point utilizzata in SAS o il mio test sta facendo qualcosa di sbagliato? –

1

È possibile elaborare in parallelo, tuttavia il disco rigido può leggere solo un pezzo di dati alla volta. Se si legge nel file con un singolo thread, è possibile elaborare i dati con diversi thread.

15

La domanda più importante qui è qual è il collo di bottiglia nel tuo caso.

Se il collo di bottiglia è il disco IO, non c'è molto che si possa fare nella parte software. Parallelizzare il calcolo non farà che peggiorare le cose, poiché la lettura simultanea del file da parti diverse peggiorerà le prestazioni del disco.

Se il collo di bottiglia è potenza di elaborazione e si dispone di più core CPU, è possibile trarre vantaggio dall'avvio di più thread per lavorare su diverse parti del file. È possibile creare in modo sicuro più InputStream s o Reader s per leggere diverse parti del file in parallelo (a condizione che non si superi il limite del sistema operativo per il numero di file aperti). È possibile separare il lavoro in attività ed eseguirle in parallelo, come in questo esempio:

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

grazie Petr, ho qualcosa di simile ma usavo Runnables (vecchio modo). La mia osservazione era che solo un thread era occupato e questo è il motivo per cui ho postato questa domanda. Ritornerò presto e invieremo le mie osservazioni – user1132593

+2

Sono stato in grado di bloccare il file e leggerlo contemporaneamente. Per un .I file di testo da 5 GB qui erano i miei risultati (hh.mm.ss.SSS): chunks = [1]: 0: 18: 10.328 chunks = [2]: 0: 13: 19.125 chunks = [3]: 0: 12: 54.824 . Non c'è molta differenza. Tuttavia per me la soluzione migliore era comprimere il file e processare in serie il file zip. Ciò era dovuto all'elevato rapporto di compressione. Il file zip ha finito per essere 10 MB – user1132593

Problemi correlati