2013-05-15 9 views
12

Mój komputer jest uzbrojony w 16 rdzeni.Obniżanie wydajności przy zwiększaniu liczby rdzeni

System.out.println(Runtime.getRuntime().availableProcessors()); //16 

Używam poniższego kodu, aby zobaczyć efektywność wykorzystania moich rdzeni. Wątek „CountFileLineThread” po prostu policzyć liczbę wierszy w pliku (Istnieją 133 plików w folderze)

Biorę notatki na tej linii:

ExecutorService es = Executors.newFixedThreadPool(NUM_CORES); 

Gdzie NUM_CORES wynosi od 1 do 16

Z powyższego wyniku zauważysz, że powyżej 5 rdzeni wydajność zaczyna spadać. Nie spodziewałbym się "produktu o malejącym zwrocie" dla 6 rdzeni i więcej (przy okazji, dla 7 rdzeni zajmuje to 22 minuty, witam?!?!) Moje pytanie brzmi: dlaczego?

enter image description here

public class TestCores 
{ 
    public static void main(String args[]) throws Exception 
    { 
    long start = System.currentTimeMillis(); 
    System.out.println("START"); 

    int NUM_CORES = 1; 

    List<File> files = Util.getFiles("/Users/adhg/Desktop/DEST/"); 
    System.out.println("total files: "+files.size()); 
    ExecutorService es = Executors.newFixedThreadPool(NUM_CORES); 
    List<Future<Integer>> futures = new ArrayList<Future<Integer>>(); 
    for (File file : files) 
    { 
     Future<Integer> future = es.submit(new CountFileLineThread(file)); 
     futures.add(future); 
    } 

    Integer total = 0; 

    for (Future<Integer> future : futures) 
    { 
     Integer result = future.get(); 
     total+=result; 
     System.out.println("result :"+result); 

    } 

    System.out.println("----->"+total); 

    long end = System.currentTimeMillis(); 
    System.out.println("END. "+(end-start)/1000.0); 
} 
} 
+13

Ponieważ twój test wykonuje operacje wejścia/wyjścia pliku, prawdopodobnie trafiłeś w punkt z tym szóstym wątkiem, w którym robisz teraz zbyt wiele operacji we/wy, co spowalnia wszystko. – cmbaxter

+2

Myślę, że jest to praca związana IO, a nie praca związana z CPU. Dodanie większej liczby wątków powoduje, że dysk twardy ma nieregularny wzór na dysku, poruszając się pomiędzy kilkoma różnymi plikami (w przeciwieństwie do kolejnych pozycji dla pojedynczego pliku, co jest oczekiwane na regularnie defragmentowanym dysku w nowoczesnym systemie operacyjnym). – nhahtdh

+1

W przypadku tego rodzaju testu sama liczba rdzeni nie ma znaczenia, gdy kod działa tylko w pamięci. Po dodaniu operacji we/wy, gdy wątek czyta plik, wszystkie pozostałe muszą poczekać. –

Odpowiedz

19

Dodałem to jako komentarz, ale mam zamiar wyrzucić go tam jako odpowiedź też. Ponieważ twój test wykonuje operacje wejścia/wyjścia pliku, prawdopodobnie trafiłeś w punkt z tym szóstym wątkiem, w którym robisz teraz zbyt wiele operacji we/wy, co spowalnia wszystko. Jeśli naprawdę chcesz zobaczyć zalety 16 rdzeni, powinieneś ponownie napisać swój wątek do czytania plików, aby korzystać z nieblokujących operacji we/wy.

+0

dzięki, ma sens; Nauczyłem się czegoś nowego. – adhg

5

Moje przeczucie polega na tym, że mogłeś włożyć tak dużo obciążenia we we-wy dysku, że wszystko spowolniłeś! Zobacz wydajność we/wy w "Activity Monitor" (jeśli korzystasz z OSX). W systemie Linux użyj polecenia vmstat, aby zorientować się, co się dzieje. [Jeśli widzisz wiele ciężkich lub wysoki wskaźnik odczytuje i zapisuje/s/s potem idziesz]


Niewiele rzeczy zauważyłem:

CountFileLineThread nie jest w kodzie. Proszę go umieścić, abyśmy mogli dokładnie zobaczyć, co się dzieje.

Następnie

for (Future<Integer> future : futures) 
{ 
    Integer result = future.get(); 
    total+=result; 
    System.out.println("result :"+result); 

} 

Tu uwaga, że ​​są zablokowane na od wyniku pierwszego Task (future.get()). W międzyczasie inne wyniki mogą być już dostępne, ale nie można ich zobaczyć, dopóki nie zostaną wykonane pierwsze. Zamiast tego użyj CompletionService, aby uzyskać wyniki w kolejności, w jakiej kończą dla lepszego pomiaru. Nie ma to jednak znaczenia, ponieważ chcesz, aby wszystkie wątki zostały wykonane przed zakończeniem timera.

Kolejny punkt: Blokowanie we/wy jest kluczem. Nie ma znaczenia, ile ma rdzeni, jeśli zadania są blokowane na I/O, sieci itp. Nowoczesne procesory mają to, co jest Hyper Threading i mogą uruchamiać wątek oczekujący na uruchomienie, jeśli aktualnie wykonuje się bloki wątków .

Na przykład, jeśli mam 16 rdzeni i spawnuję 16 wątków, prosząc ich o odczytanie plików o wielkości 1 GB, nie dostanę poprawy wydajności tylko dzięki większej liczbie rdzeni. Wąskim gardłem jest dysk i pamięć.

1

Dodawanie procesorów powoduje różnego rodzaju problemy, ale najczęściej mają do czynienia z synchronizacją między procesorami. Blokowanie na poziomie zadania w systemie plików itp. Może stać się problemem, ale jeszcze większym problemem jest synchronizacja między rdzeniami, które muszą występować tylko po to, aby zachować spójność pamięci podręcznej, śledzić zmienione strony itp.Nie wiem, ile rdzenie ma każdy chip (zrezygnowałeś z śledzenia tego problemu około 10 lat temu), ale generalnie, gdy zaczniesz synchronizować wydajność off-chipu, przestanie działać.

Dodam, że JVM może tutaj dokonać zasadniczej zmiany. Wymagana jest staranna konstrukcja JVM w celu zminimalizowania liczby współdzielonych (i często aktualizowanych) linii pamięci podręcznej, a do sprawnego działania GC w środowisku wielordzeniowym niezbędny jest niesamowity wysiłek.

Powiązane problemy