Dlaczego używanie większej liczby wątków powoduje, że jest wolniejsze niż używanie mniejszej liczby wątków

30

Próbowałem uruchomić program X przy użyciu 8 wątków i skończył się za n minut .
Próbowałem uruchomić ten sam program przy użyciu 50 wątków i zakończyło się to za n * 10 minut .

Dlaczego tak się dzieje i jak uzyskać optymalną liczbę wątków, których mogę użyć?

PoGibas
źródło

Odpowiedzi:

33

To jest skomplikowane pytanie, które zadajesz. Bez wiedzy o naturze twoich wątków trudno powiedzieć. Kilka rzeczy do rozważenia przy diagnozowaniu wydajności systemu:

Jest procesem / wątkiem

  • Ograniczone do procesora (wymaga dużej ilości zasobów procesora)
  • Powiązane z pamięcią (wymaga dużej ilości zasobów pamięci RAM)
  • Powiązane operacje we / wy (zasoby sieciowe i / lub dysk twardy)

Wszystkie te trzy zasoby są skończone i każdy może ograniczyć wydajność systemu. Musisz sprawdzić, które (razem 2 lub 3) Twoja konkretna sytuacja pochłania.

Możesz użyć ntopi iostatoraz vmstatdo zdiagnozowania, co się dzieje.

slm
źródło
8
Sprzęt też ma znaczenie. Fizyczne, wirtualne, liczba rdzeni, rodzaj rdzenia, pamięć podręczna L1 / L2 / L3 itp.
EightBitTony
46

"Dlaczego to się dzieje?" jest dość łatwy do odpowiedzi. Wyobraź sobie, że masz korytarz, w którym zmieści się cztery osoby obok siebie. Chcesz przenieść wszystkie śmieci z jednego końca na drugi koniec. Najbardziej efektywna liczba osób to 4.

Jeśli masz 1-3 osoby, tracisz przestrzeń na korytarzu. Jeśli masz 5 lub więcej osób, przynajmniej jedna z tych osób cały czas utknęła w kolejce za inną osobą. Dodanie coraz większej liczby osób po prostu zatyka korytarz, nie przyspiesza to aktywności.

Chcesz mieć tyle osób, ile możesz zmieścić, nie powodując żadnych kolejek. To, dlaczego masz kolejkę (lub wąskie gardła), zależy od pytań zawartych w odpowiedzi SLM.

EightBitTony
źródło
1
Twój przykład wprowadza w błąd. Lepiej byłoby powiedzieć coś w stylu: „Masz korytarz, w którym zmieścisz cztery osoby obok siebie i będzie on używany przez ciebie i inne osoby do różnych zadań. Sędzia decyduje, kto może przejść przez korytarz Następnie najskuteczniejsza liczba osób jest większa niż 4 i mniejsza niż pewna liczba, gdzie twoi ludzie zaczynają stać w kolejce [wysoce zależne od kontekstu] ”. Zwykle niektóre wątki powyżej liczby procesorów działają lepiej niż przy użyciu dokładnie 4 wątków. Jeśli tylko ty używasz procesora, to 4jest to najlepszy numer.
Bakuriu
7
Świetny przykład +1. Bakuriu, to przykład ilustrujący problem ograniczonego zasobu współdzielonego. To wyjaśnia problem, a nie jak znaleźć optymalną liczbę wątków.
Bananguin,
1
Warto również pamiętać, że wątki nadal mają swój własny rodzaj przełączania kontekstu. Zwiększenie liczby wątków nie zwiększa wydajności (jak wskazałeś), ale także zmniejsza czas pracy procesora, dając jądrze więcej pracy. Zasadniczo zmniejszają się zwroty z wątków, a zbyt wiele powoduje powrót wydajności.
Bratchley,
9
Każdy problem można opisać na wielu poziomach złożoności. Zaproponowałem przybliżenie problemu, które moim zdaniem jest przydatne do wyjaśnienia podstaw. Oczywiście może być bardziej wyrafinowany i bardziej szczegółowy, ale im bardziej szczegółowy, tym mniej użyteczny jako wprowadzenie do problemu.
EightBitTony
Chciałbym tylko dodać, że zamiast spędzać dużo czasu na obliczaniu optymalnej liczby wątków, po prostu kodujcie to, aby można je było łatwo zmienić. Wszelkie takie duże scalenia będą wymagały licznych testów (większość z małymi podzbiorami danych), aby je udoskonalić. Zwiększ liczbę wątków, aż zobaczysz duży spadek wydajności lub wpływ na inną aktywność systemu jest nie do przyjęcia.
DocSalvager,
20

Częstym zaleceniem jest n + 1 wątków, gdzie n jest liczbą dostępnych rdzeni procesora. W ten sposób n wątków może pracować z procesorem, podczas gdy 1 wątek czeka na dyskowe operacje we / wy. Posiadanie mniejszej liczby wątków nie wykorzysta w pełni zasobu procesora (w pewnym momencie zawsze będzie czekało na We / Wy), posiadanie większej liczby wątków spowoduje, że wątki będą walczyły o zasoby procesora.

Wątki nie są wolne, ale mają narzuty kontekstowe i - jeśli dane muszą być wymieniane między wątkami, co zwykle ma miejsce - różne mechanizmy blokujące. Jest to warte kosztu tylko wtedy, gdy masz więcej dedykowanych rdzeni procesora do uruchamiania kodu. Na jednordzeniowym procesorze pojedynczy proces (bez osobnych wątków) jest zwykle szybszy niż jakiekolwiek wykonane wątki. Wątki nie magicznie przyspieszają procesora, to po prostu dodatkowa praca.

frostschutz
źródło
To powinna być ogólna odpowiedź, biorąc pod uwagę ilość dostępnych informacji. nie potrzebujemy pełnej tezy i filozofii, jak inne odpowiedzi
Allahjane
9

Jako drugi podkreśliło ( SLM odpowiedź , EightBitTony odpowiedź ) jest to skomplikowane pytanie i bardziej, że nie opisują co thred robisz i jak to zrobić.

Ale definitywne dodanie większej liczby wątków może pogorszyć sytuację.

W dziedzinie obliczeń równoległych istnieje prawo Amdahla, które może mieć zastosowanie (lub nie może, ale nie opisuj szczegółów swojego problemu, więc ...) i może dać ogólny wgląd w tę klasę problemów.

Istotą prawa Amdahla jest to, że w każdym programie (w dowolnym algorytmie) zawsze jest procent, który nie może być uruchomiony równolegle ( część sekwencyjna ), i jest inny procent, który może być uruchomiony równolegle ( część równoległa ) [Oczywiście te dwie porcje sumują się do 100%].

Te części można wyrazić jako procent czasu wykonania. Na przykład 25% czasu może być poświęcone na ściśle sekwencyjne operacje, a pozostałe 75% czasu spędzone jest na działaniu, które można wykonać równolegle.

Zdjęcie z Wikipedii (Zdjęcie z Wikipedii )

Prawo Amdahla przewiduje, że dla każdej podanej równoległej części (np. 75%) programu możesz przyspieszyć wykonywanie tylko do tej pory (np. Maksymalnie 4 razy), nawet jeśli używasz coraz większej liczby procesorów do wykonania pracy.

Zasadą jest, że im więcej z was program nie może przekształcić w równoległe wykonywanie, tym mniej można uzyskać za pomocą większej liczby jednostek wykonawczych (procesorów).

Biorąc pod uwagę, że używasz wątków (a nie fizycznych procesorów), sytuacja może być jeszcze gorsza. Pamiętaj, że wątki mogą być przetwarzane (w zależności od implementacji i dostępnego sprzętu, np. Procesorów / rdzeni) współdzielących ten sam fizyczny procesor / rdzeń (jest to forma wielozadaniowości, jak wskazano w innej odpowiedzi).

Ta teoretyczna prognoza (o czasach procesora) nie uwzględnia innych praktycznych wąskich gardeł jako

  1. Ograniczona prędkość we / wy („szybkość” dysku twardego i sieci)
  2. Limity wielkości pamięci
  3. Inne

może to być łatwo czynnikiem ograniczającym w praktycznych zastosowaniach.

DavAlPi
źródło
To musi być wybrana odpowiedź.
Eonil,
6

Winowajcą powinno być tutaj „PRZEŁĄCZANIE KONTEKSTU”. Jest to proces zapisywania stanu bieżącego wątku, aby rozpocząć wykonywanie innego wątku. Jeśli pewna liczba wątków ma ten sam priorytet, należy je przełączać do momentu zakończenia wykonywania.

W twoim przypadku, gdy jest 50 wątków, zachodzi dużo przełączania kontekstu w porównaniu z uruchomieniem tylko 10 wątków.

Ten narzut czasowy wprowadzony z powodu przełączania kontekstu powoduje, że twój program działa wolno

x-treme
źródło
Ponieważ nie wiemy, jakie są wątki, wydaje się to zgadywać. Tak, przełączanie kontekstu dodaje narzut, ale jeśli wątki wykonują jakąś analizę danych, problemem mogą być problemy z pamięcią podręczną (tj. Niemożność użycia pamięci podręcznej, ponieważ za każdym razem, gdy przełączasz wątki, musisz ją opróżnić).
EightBitTony
Przełączanie kontekstu wątków samo w sobie , chyba że mamy do czynienia z ogromną liczbą przełączników kontekstu, prawdopodobnie nie będzie miało wpływu rzędu wydajności na wydajność. 50 wątków jest wysoka, ale nie ekstremalna (teraz na moim pudełku ps ax | wc -lzgłasza 225 procesów i wcale nie jest mocno obciążona). Skłaniam się ku zgadywaniu @ EightBitTony; unieważnienie pamięci podręcznej jest prawdopodobnie większym problemem, ponieważ za każdym razem, gdy opróżniasz pamięć podręczną, procesor musi czekać eony na kod i dane z pamięci RAM.
CVn
3

Aby naprawić metaforę EightBitTony:

"Dlaczego to się dzieje?" jest dość łatwy do odpowiedzi. Wyobraź sobie, że masz dwa baseny, jeden pełny i jeden pusty. Chcesz przenieść całą wodę z jednego na drugi i mieć 4 wiadra . Najbardziej efektywna liczba osób to 4.

Jeśli masz 1-3 osoby, tracisz dostęp do niektórych wiader . Jeśli masz 5 lub więcej osób, przynajmniej jedna z nich utknęła i czeka na wiadro . Dodawanie coraz większej liczby osób ... nie przyspiesza aktywności.

Więc chcesz mieć tyle osób, ile jest w stanie wykonać trochę pracy (użyj wiadra) jednocześnie .

Osoba tutaj jest wątkiem, a wiadro reprezentuje dowolny zasób wykonania, który stanowi wąskie gardło. Dodanie kolejnych wątków nie pomaga, jeśli nic nie mogą zrobić. Ponadto powinniśmy podkreślić, że przekazywanie wiadra od jednej osoby do drugiej jest zwykle wolniejsze niż pojedyncza osoba, która niosą wiadro na tę samą odległość. Oznacza to, że dwa wątki na przemian na rdzeniu zwykle wykonują mniej pracy niż pojedynczy wątek działający dwa razy dłużej: wynika to z dodatkowej pracy wykonanej w celu przełączania między dwoma wątkami.

To, czy ograniczającym zasobem wykonawczym (segmentem) jest procesor, rdzeń, czy hiper-wątkowy potok instrukcji, zależy od tego, która część architektury jest czynnikiem ograniczającym. Zauważ też, że zakładamy, że wątki są całkowicie niezależne. To jest tylko w przypadku, gdy mają one żadnych danych (i uniknąć kolizji cache).

Jak zasugerowało kilka osób, dla We / Wy ograniczającym zasobem może być liczba użytecznych operacji kolejkowania we / wy: może to zależeć od wielu czynników sprzętowych i jądra, ale może być znacznie większe niż liczba rdzenie. Tutaj przełącznik kontekstu, który jest tak kosztowny w porównaniu do kodu związanego z wykonaniem, jest dość tani w porównaniu do kodu związanego z We / Wy. Niestety myślę, że metafora wymknie się spod kontroli, jeśli spróbuję to uzasadnić wiadrami.

Należy zauważyć, że optymalne zachowanie z kodem związanym z We / Wy zwykle nadal ma najwyżej jeden wątek na potok / rdzeń / procesor. Należy jednak napisać asynchroniczny lub synchroniczny / nieblokujący kod we / wy, a stosunkowo niewielka poprawa wydajności nie zawsze uzasadnia dodatkową złożoność.


PS. Mój problem z oryginalną metaforą korytarza zdecydowanie sugeruje, że powinieneś mieć 4 kolejki ludzi, z 2 kolejkami niosącymi śmieci i 2 wracającymi, by zebrać więcej. Następnie można zrobić każdą kolejkę prawie tak długo, jak na korytarzu i dodanie ludzie zrobili przyspieszenia algorytmu (w zasadzie odwrócił cały korytarz na taśmociągu).

W rzeczywistości ten scenariusz jest bardzo podobny do standardowego opisu związku między opóźnieniem a rozmiarem okna w sieci TCP, dlatego wyskoczył na mnie.

Bezużyteczny
źródło
To nie jest metafora, to przybliżenie mające na celu wyjaśnienie systemu ludziom w taki sposób, aby mogli go łatwo wizualizować. Jako takie, zawsze będą „niszczone” przez osoby, które znają kolejny poziom szczegółowości, ale nie zdają sobie sprawy, że ich poziom szczegółowości nie jest w rzeczywistości niezbędny dla początkujących. Nikt nie uczy się fizyki cząstek, zaczynając od stopnia doktora. Wszystkie te rzeczy są przybliżeniem, w które stopniowo wprowadzasz, dopracowując je w miarę upływu czasu. To nie jest „złe”, to po prostu nie pełny obraz.
EightBitTony
Nikt nie jest zdezorientowany, jakiej postaci mowy użyłeś i nie jest to zła analogia. Każda analogia ma pewien limit, powyżej którego odbiega od rzeczy, którą ma opisać i przestaje być przydatna. Wspomniałem o tym tylko dlatego, że oryginał tak bardzo przypominał mi inny scenariusz i ponieważ nie sądzę, aby ta wersja była bardziej złożona ze względu na (miejmy nadzieję) lepszą przewidywalność.
Bezużyteczne
0

Jest to dość proste i łatwe do zrozumienia. Mając więcej wątków niż obsługuje procesor, tak naprawdę serializujesz, a nie równolegle. Im więcej wątków masz, tym wolniejszy będzie Twój system. Twoje wyniki są w rzeczywistości dowodem tego zjawiska.

Bruno Taboada
źródło