Domanda

Ho un file di dimensioni 2 GB che contiene record di studenti. Devo trovare studenti in base a determinati attributi in ogni record e creare un nuovo file con risultati. L'ordine degli studenti filtrati dovrebbe essere lo stesso del file originale. Qual è il modo più efficiente e più veloce di farlo usando API e thread Java IO senza avere problemi di memoria? La dimensione MAXHEAP per JVM è impostata su 512 MB.

È stato utile?

Soluzione

  1. 2 GB per un file è enorme, dovresti scegliere un DB.
  2. Se vuoi davvero usare Java i/O API, Quindi prova questo: Gestione di grandi file di dati in modo efficiente con Java e questo: Tuning Java I/O Performance

Altri suggerimenti

Che tipo di file? Basato sul testo, come CSV?

Il modo più semplice sarebbe quello di fare qualcosa come Grep: leggi la riga del file per riga, analizza la riga, controlla il criterio del filtro, se abbinato, output una riga di risultato, quindi vai alla riga successiva, fino a quando il file non è finito. Questo è molto efficiente dalla memoria, poiché hai solo la linea corrente (o un buffer un po 'più grande) caricata contemporaneamente. Il tuo processo deve leggere l'intero file solo una volta.

Non credo che più thread aiuteranno molto. Renderebbe le cose molto più complicate, e poiché il processo sembra essere vincolato I/O comunque, cercando di leggere lo stesso file con più thread probabilmente non migliora il throughput.

Se scopri che devi farlo spesso e passare attraverso il file ogni volta è troppo lento, devi costruire una sorta di indice. Il modo più semplice per farlo sarebbe importare il file in un DB (può prima essere un DB incorporato come SQLite o HSQL).

Non lo comparerei eccessivamente fino a quando non scoprirai che il modo noiosamente semplice non funziona per ciò di cui hai bisogno. Essenzialmente devi solo:

  • Apri il flusso di input sul file da 2 GB, ricordando al buffer (ad esempio avvolto con bufferedInputStream)
  • Apri il flusso di output per il file filtrato che stai per creare
  • Leggi il primo record dal flusso di input, guarda qualsiasi attributo per decidere se lo "ne hai bisogno"; Se lo fai, scrivilo al file di output
  • Ripeti per i record rimanenti

Su uno dei miei sistemi di test con hardware estremamente modesto, BufferedInputStream attorno a FileInputStream fuori dalla scatola leggi circa 500 MB in 25 secondi, cioè probabilmente meno di 2 minuti per elaborare il tuo file da 2 GB e la dimensione del buffer predefinita è fondamentalmente buona come si ottiene (Vedi il Tempi di bufferedInputStream Ho realizzato per maggiori dettagli). Immagino con l'hardware all'avanguardia è del tutto possibile che il tempo venga dimezzato.

Sia che tu debba fare molti sforzi per ridurre i 2/3 minuti o semplicemente andare per un po 'mentre stai aspettando che correre è una decisione che dovrai prendere a seconda delle tue esigenze. Penso che l'opzione del database non ti comprerà molto a meno che tu non debba eseguire molte diverse elaborazioni sullo stesso set di dati (e ci sono altre soluzioni a questo che non significano automaticamente il database).

Penso che dovresti usare memoria mappata files. Questo ti aiuterà a mappare il file più grande su una memoria più piccola. Questo si agirà come una memoria virtuale e per quanto riguarda le prestazioni i file mappati sono i più veloci di Write/Read.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top