2012-08-08 17 views
21

Mam duży plik, który przetwarza wiele godzin. Zastanawiam się więc nad próbą oszacowania kawałków i równoległego czytania fragmentów. Czy możliwe jest równoczesne czytanie jednego pliku? Sprawdziłem zarówno RandomAccessFile, jak i nio.FileChannel, ale na podstawie innych postów nie jestem pewien, czy to podejście zadziała. sugestia !!Równoczesne czytanie pliku (java preffered)

+0

Który system operacyjny? Java lub nie, Windows nie radzi sobie dobrze z tego rodzaju rzeczami – SJuan76

+0

Czytałem gdzieś, że gdy jest to diskio, możesz nie zyskać przewagi konkurencyjnej. – kosa

+2

Dlaczego upadek? Uważam, że to pytanie jest bardzo interesujące. – hectorg87

Odpowiedz

1

Jeśli czytasz plik z dysku twardego, najszybszym sposobem uzyskania danych jest odczytanie pliku od początku do końca, to znaczy, nie równolegle.

Jeśli przetwarzanie zajmuje więcej czasu, może to przynieść korzyść z faktu, że kilka wątków przetwarza jednocześnie różne porcje danych, ale to nie ma nic wspólnego z czytaniem pliku.

+1

Myślę, że to nie odpowiada na pytanie. Pytanie brzmi: czy możliwe jest "równoległe" odczytanie dużego pliku? – hectorg87

+0

Byłem pod wrażeniem, że podstawowe pytanie było bardziej w miejscu pobytu "Czy mogę odczytać plik szybciej przez porównanie odczytu?" – Buhb

+1

Po edycji: Myślę, że ma to związek z odczytem, ​​ponieważ jest to "duży plik", jak stwierdził. btw, -1 nie jest ode mnie – hectorg87

7

Możesz dokonać paralelizacji czytania dużego pliku pod warunkiem, że masz wielu niezależnych spindali. Na przykład. jeśli posiadasz system plików z zerowym zerowaniem Raid 0 + 1, możesz zobaczyć poprawę wydajności, uruchamiając wiele jednoczesnych odczytów do tego samego pliku.

Jeśli jednak masz połączony system plików, taki jak Raid 5 lub 6 lub zwykły pojedynczy dysk. Jest bardzo prawdopodobne, że czytanie tego pliku sekwencyjnie jest najszybszym sposobem odczytu z tego dysku. Uwaga: system operacyjny jest wystarczająco inteligentny, aby wstępnie pobierać odczyty, gdy zobaczy, że czytasz sekwencyjnie, więc użycie dodatkowego wątku w tym celu raczej nie pomoże.

tj. Użycie wielu wątków nie przyspieszy działania dysku.

Jeśli chcesz szybciej odczytać zawartość dysku, użyj szybszego dysku. Typowy dysk twardy SATA może odczytać około 60 MB/s i wykonać 120 operacji IOPS. Typowy dysk SATA SSD może odczytać z szybkością około 400 MB/s i wykonać 80 000 operacji IOPS, a typowy dysk PCI SSD może odczytać z szybkością 900 MB/s i wykonać 230 000 operacji IOPS.

+0

Peter, Issue jest z jednym plikiem na moim dysku twardym. W przypadku RAID itp. W jaki sposób mogę podzielić plik? – user1132593

+0

RAID automatycznie podzieli plik, jeśli użyjesz stripingu (lub RAID 1, który skopiuje go na dwa dyski) RAID 5 i 6 mogą uzyskać korzyści z usuwania, ale zależy to od kontrolera, ponieważ często są one zoptymalizowane pod kątem maksymalnej przepustowości, np. Odczyty sekwencyjne . –

+1

Przeprowadzam test dla tego samego przypadku użycia - odczytywanie pojedynczego pliku z wielu wątków. Stwierdziłem, że posiadanie wielu wątków poprawia wydajność, jeśli podstawową pamięcią jest napęd dysków SATA, a jednocześnie poprawia wydajność, jeśli jest dyskiem SAS. Czy byłby to skutek technologii punkt-punkt zastosowanej w SAS, czy też mój test robi coś niepoprawnego? –

1

Można przetwarzać równolegle, jednak dysk twardy może odczytać tylko jedną porcję danych na raz. Jeśli czytasz w pliku z jednym wątkiem, możesz przetworzyć dane z kilkoma wątkami.

15

Najważniejszym pytaniem tutaj jest jakie jest wąskie gardło w twoim przypadku.

Jeśli wąskim gardłem jest Twój dysk IO, to nie można wiele zrobić w oprogramowaniu. Równoległe obliczenia tylko pogorszą sytuację, ponieważ czytanie pliku z różnych części jednocześnie spowoduje pogorszenie wydajności dysku.

Jeśli wąskim gardłem jest moc przetwarzania, a masz wiele rdzeni procesora, możesz wykorzystać zalety uruchamiania wielu wątków do pracy nad różnymi częściami pliku. Możesz bezpiecznie utworzyć kilka różnych InputStream s lub Reader s, aby równolegle odczytywać różne części pliku (o ile nie przekroczymy limitu liczby otwartych plików w systemie operacyjnym). Można podzielić pracę na zadania i uruchamiać je równolegle, tak jak w tym przykładzie:

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

dzięki Petr, mam coś podobnego, ale używałem Runnables (stary sposób). Moja uwaga była taka, że ​​tylko jeden wątek był zajęty i dlatego wysłałem to pytanie. Wkrótce spróbuję ponownie i opublikuję moje obserwacje. – user1132593

+2

Udało mi się porąbać plik i czytać go jednocześnie. Dla .Tutaj plik tekstowy 5GB zawierał moje wyniki (hh.mm.ss.SSS): chunks = [1]: 0: 18: 10.328 chunk = [2]: 0: 13: 19.125 chunk = [3]: 0: 12: 54.824 . Niewielka różnica. Jednak dla mnie najlepszym rozwiązaniem było zip plik i szeregowo przetwarzać plik zip. Wynikało to z wysokiego współczynnika kompresji. Plik zip zakończył się 10 MB – user1132593