2011-11-10 14 views
5

Mam następujący kod:Dlaczego ta pętla Parallel.ForEach nie poprawia wydajności?

  if (!this.writeDataStore.Exists(mat)) 
      { 
       BlockingCollection<ImageFile> imageFiles = new BlockingCollection<ImageFile>(); 
       Parallel.ForEach(fileGrouping, fi => DecompressAndReadGzFile(fi, imageFiles)); 


       this.PushIntoDb(mat, imageFiles.ToList()); 
      } 

DecompressAndReadGzFile jest metodą statyczną w tej samej klasie, że metoda ta jest zawarta w Zgodnie z nazwą metody ja dekompresji i odczytu plików gz, wiele z nich, to znaczy w górę. do 1000, więc narzut równoległości jest warty dla korzyści. Jednak nie widzę korzyści. Kiedy używam profilera wydajności ANTS widzę, że działają one dokładnie w tych samych czasach, jak gdyby nie wystąpiła równoległość. Sprawdzam również rdzenie procesora za pomocą eksploratora procesów i wygląda na to, że prawdopodobnie praca jest wykonywana na dwóch rdzeniach, ale jeden rdzeń wydaje się wykonywać większość pracy. Czego nie rozumiem, jeśli chodzi o równoległe dekompresowanie i odczytywanie plików Parallel.ForEach?

ZAKTUALIZOWANE PYTANIE: Jaki jest najszybszy sposób na odczytanie informacji z listy plików?

Problem (uproszczony):

  1. Istnieje duża lista plików .gz (1200).
  2. Każdy plik ma wiersz zawierający "DATA:", lokalizacja i numer linii nie są statyczne i mogą się różnić w zależności od pliku.
  3. Musimy odzyskać pierwszy numer po „dane” (tylko dla uproszczenia) i przechowywać go w obiekt w pamięci (np List)

W pierwszym pytaniu używałem równoległym .Dla pętli, ale nie wydaje mi się, aby procesor był związany z więcej niż 1 rdzeniem.

+0

Czy synchronizacja została wykonana w 'DecompressAndReadGzFile'? – SimonC

+0

Nie jestem tego świadomy. Chociaż istnieje wywołanie funkcji imageFiles.Add, która automatycznie dodaje blokadę z tego, co rozumiem. – Seth

Odpowiedz

12

Czy to możliwe, że wątki spędzają większość czasu, czekając na IO? Przez czytanie wielu plików na raz, możesz spowodować, że dysk będzie bardziej thrashowy niż w przypadku pojedynczej operacji. Możliwe, że możesz poprawić wydajność, używając pojedynczego wątku czytającego sekwencyjnie, ale potem podrzucając dekompresję związaną z procesorem do oddzielnych wątków ... ale może się okazać, że tak naprawdę potrzebujesz tylko jednego wątku wykonującego dekompresję i tak, jeśli dysk jest wolniejszy niż sam proces dekompresji.

Jednym ze sposobów sprawdzenia tego jest skopiowanie najpierw plików wymagających dekompresji na ramdysk i nadal używanie aktualnego kodu. Podejrzewam, że okaże się, że jesteś związany z procesorem, a wszystkie procesory są zajęte prawie przez cały czas.

(Należy również rozważyć, co robisz ze po dekompresji plików. Piszesz te z powrotem do dysku? Jeśli tak, to znowu nie ma możliwości, że jesteś w zasadzie czeka na dysku lanie.)

+0

Nie piszę zdekompresowanych plików na dysk. Czytam pliki compress do pamięci przy użyciu GZipStream, tworząc TextREader, aby wyodrębnić to, co potrzebne, umieszczając je w kolekcji imageFiles w powyższym kodzie. Mogę jednak wypróbować twoją sugestię dysku RAM. – Seth

+0

@Seth: Zauważ, że sugestia RAMdysku jest naprawdę * tylko *, aby sprawdzić, czy jesteś związany z IO, a nie CPU.Jeśli tak, to po prostu skończysz przenosić koszty na etap "kopiowania danych na ramdysk". –

+0

Pamiętasz sterowniki oprogramowania dysku twardego Turbo Booster lata temu? Szybsze operacje we/wy dysku przez kompresję danych w pamięci, a następnie zapisanie skompresowanych danych na dysku. – dthorpe

0

jest jakaś szansa, że ​​twoja statyczna metoda współużytkuje jakiekolwiek globalne zasoby wśród swoich połączeń. Ponieważ w takim przypadku ta statyczna metoda będzie wywoływana sekwencyjnie i bez równoległych korzyści. Czy możesz umieścić kod klasy fileGrouping?