2012-07-31 16 views
6

Ho seguente codice:Java elaborazione dei file parallela

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 ; 
} 

} 

Dove sto cercando di contare il numero di partite in un array con due file. Ora, anche se lo sto eseguendo su due thread, il codice non sta andando bene perché:

(eseguendolo su thread singolo, file 1 + tempo di lettura file 2) < (file 1 || tempo di lettura del file 2 in thread multipli).

Qualcuno può aiutarmi a risolvere questo (ho 2 core CPU e dimensioni del file è di circa 1,5 GB).

+0

@SurajChandran, la maggior parte delle volte. E davvero nessun effetto. :) Basta eseguire un test. – Arpssss

+0

I file non sono da 1,5 GB, sono solo ~ 80K. –

+0

@KeithRandall, ho appena dato l'uso di esempio. – Arpssss

risposta

7

Nel primo caso si legge sequenzialmente un file, byte per byte, blocco per blocco. Questo è veloce quanto l'I/O del disco può essere, a condizione che il file non sia molto frammentato. Quando hai finito con il primo file, disk/OS trova l'inizio del secondo file e continua la lettura lineare del disco molto efficiente.

Nel secondo caso si passa continuamente dal primo al secondo file, forzando il disco a cercare da un luogo all'altro. Questo tempo di ricerca extra (circa 10 ms) è la radice della tua confusione.

Oh, e sapete che l'accesso al disco è a thread singolo e il vostro task è legato all'I/O, quindi non vi è alcuna possibilità di dividere questa attività su più thread, a patto che leggiate dallo stesso disco fisico? Il vostro approccio potrebbe essere giustificato solo se:

  • ogni thread, tranne la lettura da un file, è stato anche l'esecuzione di alcune CPU o operazioni, più lento il blocco di un ordine di grandezza rispetto a I/O.

  • file si trovano su diversi fisiche unità (partizione diversa non è sufficiente) o su alcune configurazioni RAID

  • si utilizza un'unità SSD

+1

+1. Questo è un problema fondamentale che molte persone non capiscono: solo aumentare il reagente limitante aumenterà le prestazioni. – RedGreasel

1

Non si ottiene alcun beneficio da multithreading come Tomasz ha sottolineato leggendo i dati dal disco. Potresti ottenere un miglioramento della velocità se multithread i controlli, cioè carichi i dati dai file in array in modo sequenziale e quindi i thread eseguono il controllo in parallelo. Ma considerando la piccola dimensione dei tuoi file (~ 80kb) e il fatto che tu stia solo confrontando gli inte dubito che il miglioramento delle prestazioni varrà la pena.

Qualcosa che sicuramente migliorerà la velocità di esecuzione è se non si usa readInt(). Dato che sai che stai confrontando 20000 ints, dovresti leggere tutti i 20000 ints in una matrice per volta per ogni file (o almeno in blocchi), piuttosto che chiamare la funzione readInt() 20000 volte.

Problemi correlati