2009-10-10 20 views
7

Che cosa è un modo efficiente per un'applicazione multithread Java in cui molti thread devono leggere esattamente lo stesso file (> 1 GB di dimensione) ed esporlo come flusso di input? Ho notato che se ci sono molti thread (> 32), il sistema inizia a contendersi su I/O e ha un sacco di attesa I/O.Multithreading Java che legge un singolo file di grandi dimensioni

Ho pensato di caricare il file in un array di byte condiviso da tutti i thread: ogni thread creerebbe un ByteArrayInputStream, ma l'allocazione di un array di byte da 1 GB non funzionerebbe correttamente.

Ho anche preso in considerazione l'utilizzo di un singolo FileChannel e ogni thread che crea un InputStream su di esso utilizzando Channels.newInputStream(), tuttavia sembra che sia il FileChannel che mantiene lo stato di InputStream.

+1

Ogni thread ha bisogno dell'intero contenuto del file? O ognuno può cercare i dati rilevanti di cui ha bisogno? –

+0

Ogni thread deve leggere l'intero file. – bob

+0

Il sistema ha 8 GB di memoria e non mi dispiacerebbe assegnare un array da 1 GB. Ma la JVM non sembra proprio gradire questo: usa il 100% della CPU cercando di allocare l'array per un tempo molto lungo. – bob

risposta

10

Mi sembra che stai andando a avere per caricare il file in memoria se si desidera evitare la contesa IO. Il sistema operativo farà un po 'di buffering, ma se stai scoprendo che non è abbastanza, dovrai farlo da solo.

Hai davvero bisogno di 32 thread? Presumibilmente non hai quasi quel numero di core, quindi usa meno thread e otterrai meno switching di contesto, ecc.

I tuoi thread elaborano il file dall'inizio alla fine? In tal caso, potresti dividere efficacemente il file in blocchi? Leggi il primo (ad esempio) 10 MB di dati in memoria, lascia che tutti i thread lo elaborino, quindi passa al successivo 10 MB ecc.

Se ciò non funziona per te, quanta memoria hai confrontato con dimensione del file? Se si dispone di molta memoria ma non si desidera allocare un array enorme, è possibile leggere l'intero file in memoria, ma in molti array di byte più piccoli separati. Dovresti quindi scrivere un flusso di input che si estende su tutti quegli array di byte, ma dovrebbe essere fattibile.

+0

@jon, sarebbe possibile utilizzare gli strumenti nio per mappare una struttura Java sul file su disco, quindi tutto ciò che è necessario è scrivere la struttura java e lasciare che la JVM/OS capisca come gestire i dettagli della lettura effettiva ? –

+1

@Thorbjorn: Beh, Java supporta i file mappati in memoria, ma se si dispone di più informazioni di quelle del sistema operativo su come si utilizzerà il file, si potrebbe essere in grado di fare meglio. –

1

alcune idee:

  1. Scrivi un'implementazione InputStream personalizzato che funge da vista su un FileChannel. Scrivilo in modo tale che non si basi su nessuno stato nel FileChannel. (es .: ogni istanza dovrebbe tenere traccia della propria posizione e la lettura dovrebbe usare letture assolute sul FileChannel sottostante). Questo almeno ti mette in difficoltà con Channels.newInputStream(), ma potrebbe non risolvere i tuoi problemi di contesa IO .

  2. Scrivere un'implementazione InputStream personalizzata che funge da visualizzazione su MappedByteBuffer. La mappatura della memoria non dovrebbe essere così male come in realtà la lettura dell'intera cosa in memoria in una sola volta, ma continuerai a mangiare fino a 1 GB di spazio di indirizzi virtuali.

  3. Come il numero 1, ma con una sorta di livello di memorizzazione nella cache condiviso. Non proverei questo a meno che 1 non sia abbastanza efficiente e 2 non sia fattibile. In realtà, il sistema operativo dovrebbe già fare un po 'di cache per te al primo posto, quindi qui stai essenzialmente cercando di essere più intelligente del caching del filesystem del sistema operativo.

5

è possibile aprire il file più volte in modalità di sola lettura. Puoi accedere al file nel modo che preferisci. Basta lasciare la cache al sistema operativo. Quando è troppo lento, potresti prendere in considerazione una sorta di cache basata su blocchi in cui tutti i thread possono accedere alla stessa cache.

0

Questo è un file molto grande. Riesci a ottenere il file consegnato come un insieme più piccolo di file? La semplice consegna di questo file sarà un grande lavoro anche su una rete aziendale.

A volte è più semplice modificare il processo rispetto al programma.

Potrebbe anche essere meglio scrivere qualcosa per dividere il file in un numero di blocchi e elaborarli separatamente.

Problemi correlati