Wielowątkowość: jaki jest sens większej liczby wątków niż rdzeni?

142

Pomyślałem, że celem komputera wielordzeniowego jest to, że może uruchamiać wiele wątków jednocześnie. W takim przypadku, jeśli masz maszynę czterordzeniową, jaki jest sens jednoczesnego uruchamiania więcej niż 4 wątków? Czy nie kradną sobie po prostu czasu (zasobów procesora)?

Nick Heiner
źródło
52
lubimy tego typu pytania, kwestionują one fundamentalne kwestie, które są uważane za
oczywiste… nie przestawaj
6
Kiedy ostatnio miałeś Firefox, MS Word, Winamp, Eclipse i menedżera pobierania (więcej niż cztery programy / procesy) uruchomione jednocześnie na czterordzeniowym komputerze? Ponadto pojedyncza aplikacja może czasami odrodzić więcej niż cztery wątki - co powiesz na to?
Amarghosh
1
Kradzież niekoniecznie jest zła. Możesz mieć wątek o wyższym priorytecie dotyczący ważnych zadań, które wymagają kradzieży czasu.
kichik
1
@Amarghosh Myślę, że to było pytanie, dlaczego pojedyncza aplikacja może chcieć tworzyć więcej wątków niż rdzeni, jeśli nie wydaje się, aby przynosiło to jakiekolwiek korzyści wydajnościowe. Twój przykład z więcej niż czterema programami nie jest tutaj odpowiedni. Jak słusznie zauważyłeś, są to procesy. Funkcja wielozadaniowości systemu operacyjnego (multipleksowanie procesów) ma bardzo niewiele wspólnego z wątkami w ramach jednego procesu.
Aleksandr Ivannikov

Odpowiedzi:

81

Odpowiedź obraca się wokół celu wątków, którym jest równoległość: uruchomienie kilku oddzielnych linii wykonania jednocześnie. W „idealnym” systemie miałbyś wykonywać jeden wątek na rdzeń: bez przerw. W rzeczywistości tak nie jest. Nawet jeśli masz cztery rdzenie i cztery wątki robocze, Twój proces i jego wątki będą stale przełączane na inne procesy i wątki. Jeśli używasz dowolnego nowoczesnego systemu operacyjnego, każdy proces ma co najmniej jeden wątek, a wiele ma więcej. Wszystkie te procesy działają jednocześnie. Prawdopodobnie masz teraz kilkaset wątków uruchomionych na komputerze. Nigdy nie dojdzie do sytuacji, w której wątek będzie działał bez „kradzieży” czasu. (Cóż, możesz, jeśli działa w czasie rzeczywistym, jeśli używasz systemu operacyjnego czasu rzeczywistego lub nawet w systemie Windows użyj priorytetu wątków w czasie rzeczywistym. Ale to rzadkie.)

Biorąc to pod uwagę jako tło, odpowiedź: tak, więcej niż cztery wątki na prawdziwej czterordzeniowej maszynie mogą spowodować sytuację, w której „kradną sobie czas”, ale tylko wtedy, gdy każdy pojedynczy wątek potrzebuje 100% procesora . Jeśli wątek nie działa w 100% (ponieważ wątek interfejsu użytkownika może nie działać lub wątek wykonujący niewielką ilość pracy lub czekający na coś innego), to inny zaplanowany wątek jest w rzeczywistości dobrą sytuacją.

W rzeczywistości jest to bardziej skomplikowane:

  • A co, jeśli masz pięć prac, które trzeba wykonać na raz? Bardziej sensowne jest uruchomienie ich wszystkich naraz, niż uruchomienie czterech z nich, a piątego później.

  • Rzadko się zdarza, aby wątek naprawdę potrzebował 100% procesora. Na przykład w momencie, gdy używa dysku lub sieci we / wy, może potencjalnie spędzać czas na czekaniu, nie robiąc nic pożytecznego. To bardzo powszechna sytuacja.

  • Jeśli masz zadanie do wykonania, jednym z powszechnych mechanizmów jest użycie puli wątków. Wydawałoby się, że sensowne jest posiadanie takiej samej liczby wątków co rdzeni, jednak pula wątków .Net ma do 250 wątków dostępnych na procesor . Nie jestem pewien, dlaczego to robią, ale przypuszczam, że ma to związek z rozmiarem zadań, które mają być uruchamiane w wątkach.

Tak więc: kradzież czasu nie jest złą rzeczą (i tak naprawdę nie jest też kradzieżą: tak ma działać system). Pisz swoje programy wielowątkowe w oparciu o rodzaj pracy, którą wykonają wątki, a może to nie być procesor -uwiązany. Określ liczbę potrzebnych wątków na podstawie profilowania i pomiarów. Może się okazać, że bardziej przydatne będzie myślenie w kategoriach zadań lub zadań niż wątków: pisz obiekty pracy i przekazuj je do puli do uruchomienia. Wreszcie, jeśli Twój program nie jest naprawdę krytyczny dla wydajności, nie martw się zbytnio :)

David
źródło
16
+1 za „ale tylko wtedy, gdy każdy pojedynczy wątek potrzebuje 100% procesora”. To było założenie, z którego nie zdawałem sobie sprawy, że robię.
Nick Heiner
1
Wspaniała odpowiedź na świetne pytanie. Dziękuję Ci!
Edgecase
53

To, że wątek istnieje, nie zawsze oznacza, że ​​jest aktywnie uruchomiony. Wiele zastosowań wątków obejmuje niektóre wątki, które przechodzą w stan uśpienia, dopóki nie nadejdzie czas, aby coś zrobiły - na przykład dane wejściowe użytkownika wyzwalają wątki, aby się obudzić, wykonać pewne przetwarzanie i wrócić do snu.

Zasadniczo wątki to indywidualne zadania, które mogą działać niezależnie od siebie, bez konieczności zdawania sobie sprawy z postępu innego zadania. Jest całkiem możliwe, że masz ich więcej, niż masz możliwości uruchamiania jednocześnie; nadal są przydatne dla wygody, nawet jeśli czasami muszą stać w kolejce jeden za drugim.

Bursztyn
źródło
11
Dobrze powiedziane. Argument „jeden wątek na procesor” dotyczy tylko kodu związanego z procesorem. Programowanie asynchroniczne to kolejny powód, dla którego warto używać wątków.
Joshua Davis
26

Chodzi o to, że pomimo braku rzeczywistego przyspieszenia, gdy liczba wątków przekracza liczbę rdzeni, można użyć wątków do rozdzielenia elementów logiki, które nie powinny być od siebie zależne.

Nawet w średnio złożonej aplikacji, używając pojedynczego wątku, spróbuj zrobić wszystko szybko, tworząc skrót z „przepływu” kodu. Pojedynczy wątek spędza większość czasu na sprawdzaniu tego, sprawdzaniu tego, warunkowym wywoływaniu procedur w razie potrzeby, i trudno jest dostrzec cokolwiek poza grzęzawiskiem drobiazgów.

Porównaj to z przypadkiem, w którym możesz poświęcić wątki na zadania, aby patrząc na dowolny pojedynczy wątek, zobaczyć, co robi ten wątek. Na przykład jeden wątek może blokować oczekiwanie na dane wejściowe z gniazda, analizować strumień na komunikaty, filtrować komunikaty, a gdy pojawi się poprawny komunikat, przekazywać go do innego wątku roboczego. Wątek roboczy może pracować na danych wejściowych z wielu innych źródeł. Kod każdego z nich będzie wykazywał czysty, celowy przepływ, bez konieczności jawnego sprawdzania, czy nie ma nic innego do zrobienia.

Partycjonowanie pracy w ten sposób pozwala aplikacji polegać na systemie operacyjnym, aby zaplanować, co dalej z procesorem, więc nie musisz przeprowadzać jawnych warunkowych kontroli wszędzie w aplikacji, co może blokować, a co jest gotowe do przetworzenia.

JustJeff
źródło
1
To interesująca myśl ... Zawsze słyszałem, że wielowątkowość aplikacji to sumaryczny dodatek do złożoności, ale to, co mówisz, ma sens.
Nick Heiner
Wielowątkowość aplikacji zwiększa złożoność, jeśli jej obawy nie są odpowiednio rozdzielone. Jeśli jest zaprojektowany z minimalnym nakładaniem się problemów (a tym samym wspólnym stanem), jest to oszczędność netto w kwestiach złożoności.
TYLKO MOJA poprawna OPINIA
Istnieją sposoby tworzenia struktury aplikacji jednowątkowych, tak aby przepływ sterowania był bardziej przejrzysty na poziomie pisania programów. OTOH, jeśli możesz ustrukturyzować swoje wątki tak, aby przekazywały sobie nawzajem tylko wiadomości (zamiast udostępniać zasoby), łatwo jest ustalić, co się dzieje i sprawić, by wszystko działało.
Donal Fellows
1
Należy jednak zwrócić uwagę, że używanie wątków może uprościć sprawę tylko do pewnego momentu. Zbyt często próbuje się zmusić dwa wątki do wykonania pracy, którą słusznie powinien wykonać jeden, przy czym złożoność powraca w pikach. Objawami tego są nadmierne potrzeby komunikacji i synchronizacji w celu skoordynowania pożądanych rezultatów.
JustJeff,
15

Jeśli wątek oczekuje na zasób (na przykład ładowanie wartości z pamięci RAM do rejestru, dyskowe operacje we / wy, dostęp do sieci, uruchamianie nowego procesu, wysyłanie zapytań do bazy danych lub oczekiwanie na dane wejściowe użytkownika), procesor może pracować na inny wątek i powróć do pierwszego wątku, gdy zasób będzie dostępny. Zmniejsza to czas, jaki procesor spędza w stanie bezczynności, ponieważ procesor może wykonywać miliony operacji zamiast pozostawać w stanie bezczynności.

Rozważ wątek, który musi odczytywać dane z dysku twardego. W 2014 roku typowy rdzeń procesora działa z częstotliwością 2,5 GHz i może być w stanie wykonać 4 instrukcje na cykl. Przy czasie cyklu 0,4 ns procesor może wykonać 10 instrukcji na nanosekundę. Przy typowym mechanicznym czasie wyszukiwania dysku twardego wynoszącym około 10 milisekund, procesor jest w stanie wykonać 100 milionów instrukcji w czasie potrzebnym na odczytanie wartości z dysku twardego. Dyski twarde z małą pamięcią podręczną (bufor 4 MB) i dyski hybrydowe z kilkoma GB miejsca na dane mogą znacznie poprawić wydajność, ponieważ opóźnienie danych dla odczytów sekwencyjnych lub odczytów z sekcji hybrydowej może być o kilka rzędów wielkości szybsze.

Rdzeń procesora może przełączać się między wątkami (koszt wstrzymania i wznowienia wątku wynosi około 100 cykli zegara), podczas gdy pierwszy wątek czeka na wejście o dużym opóźnieniu (wszystko droższe niż rejestry (1 zegar) i pamięć RAM (5 nanosekund)). dyskowe I / O, dostęp do sieci (opóźnienie 250 ms), odczyt danych z płyty CD lub powolnej magistrali lub połączenie z bazą danych. Posiadanie większej liczby wątków niż rdzeni oznacza, że ​​można wykonywać pożyteczną pracę podczas rozwiązywania zadań o dużym opóźnieniu.

Procesor ma harmonogram wątków, który przypisuje priorytet każdemu wątkowi i pozwala wątkowi na uśpienie, a następnie wznowienie działania po z góry określonym czasie. Zadaniem programu planującego wątki jest ograniczenie wyrzucania danych, które wystąpiłoby, gdyby każdy wątek wykonał zaledwie 100 instrukcji przed ponownym uśpieniem. Narzut związany z przełączaniem wątków zmniejszyłby całkowitą użyteczną przepustowość rdzenia procesora.

Z tego powodu warto podzielić problem na rozsądną liczbę wątków. Jeśli pisałeś kod w celu wykonania mnożenia macierzy, utworzenie jednego wątku na komórkę w macierzy wyjściowej może być nadmierne, podczas gdy jeden wątek na wiersz lub na n wierszy w macierzy wyjściowej może obniżyć koszty ogólne tworzenia, wstrzymywania i wznawiania wątków.

Dlatego też ważne jest przewidywanie gałęzi. Jeśli masz instrukcję if, która wymaga załadowania wartości z pamięci RAM, ale treść instrukcji if i else używa wartości już załadowanych do rejestrów, procesor może wykonać jedną lub obie gałęzie, zanim warunek zostanie oceniony. Gdy warunek powróci, procesor zastosuje wynik z odpowiedniej gałęzi i odrzuci drugą. Wykonywanie tutaj potencjalnie bezużytecznej pracy jest prawdopodobnie lepsze niż przełączanie się na inny wątek, co może prowadzić do szarpania.

Ponieważ odeszliśmy od jednordzeniowych procesorów o dużej szybkości zegara do procesorów wielordzeniowych, projekt chipów skupił się na upychaniu większej liczby rdzeni na matrycę, poprawie współdzielenia zasobów między rdzeniami, lepszymi algorytmami przewidywania gałęzi, lepszym narzutem przełączania wątków, i lepsze planowanie wątków.

IceArdor
źródło
to samo można zrobić z pojedynczym wątkiem i kolejką: \ czy jest naprawdę jakaś korzyść z posiadania 80 wątków na 2-4 rdzeniach, w porównaniu z posiadaniem tylko 2-4 rdzeni, które po prostu zjadają zadania z kolejki, gdy tylko nadejdą i nie mają nic do roboty?
Dmitry
8

Większość powyższych odpowiedzi dotyczy wydajności i jednoczesnego działania. Podejdę do tego z innego punktu widzenia.

Weźmy przykład, powiedzmy, uproszczonego programu do emulacji terminala. Musisz wykonać następujące czynności:

  • uważaj na znaki przychodzące ze zdalnego systemu i wyświetl je
  • uważaj na rzeczy pochodzące z klawiatury i wyślij je do zdalnego systemu

(Prawdziwe emulatory terminali robią więcej, w tym potencjalnie wyświetlają echo rzeczy, które wpisujesz na wyświetlaczu, ale na razie to pominiemy).

Teraz pętla do odczytu z pilota jest prosta, zgodnie z następującym pseudokodem:

while get-character-from-remote:
    print-to-screen character

Pętla do monitorowania klawiatury i wysyłania jest również prosta:

while get-character-from-keyboard:
    send-to-remote character

Problem polega jednak na tym, że musisz to robić jednocześnie. Kod musi teraz wyglądać bardziej tak, jeśli nie masz wątków:

loop:
    check-for-remote-character
    if remote-character-is-ready:
        print-to-screen character
    check-for-keyboard-entry
    if keyboard-is-ready:
        send-to-remote character

Logika, nawet w tym celowo uproszczonym przykładzie, który nie bierze pod uwagę złożoności komunikacji w świecie rzeczywistym, jest dość zaciemniona. Jednak w przypadku wątków, nawet na jednym rdzeniu, dwie pętle pseudokodów mogą istnieć niezależnie bez przeplatania ich logiki. Ponieważ oba wątki będą w większości związane z operacjami we / wy, nie obciążają one procesora, nawet jeśli, ściśle mówiąc, marnują zasoby procesora bardziej niż zintegrowana pętla.

Oczywiście użycie w świecie rzeczywistym jest bardziej skomplikowane niż powyższe. Jednak złożoność zintegrowanej pętli rośnie wykładniczo w miarę dodawania kolejnych problemów do aplikacji. Logika staje się coraz bardziej fragmentaryczna i musisz zacząć używać technik takich jak automaty stanowe, procedury itp., Aby uzyskać możliwość zarządzania. Zarządzalne, ale nieczytelne. Wątkowanie sprawia, że ​​kod jest bardziej czytelny.

Dlaczego więc nie miałbyś używać wątków?

Cóż, jeśli twoje zadania są związane z procesorem zamiast we / wy, wątkowanie w rzeczywistości spowalnia system. Wydajność ucierpi. W wielu przypadkach. („Thrashing” to częsty problem, jeśli porzucisz zbyt wiele wątków związanych z procesorem. W efekcie spędzasz więcej czasu na zmienianiu aktywnych wątków niż na uruchamianiu zawartości samych wątków). tak proste jest to, że celowo wybrałem uproszczony (i nierealistyczny) przykład. Jeśli chcesz powtórzyć to, co zostało wpisane na ekranie, masz nowy świat bólu, gdy wprowadzasz blokowanie współdzielonych zasobów. Mając tylko jeden wspólny zasób, nie stanowi to większego problemu, ale zaczyna stawać się coraz większym problemem, ponieważ masz więcej zasobów do udostępnienia.

Ostatecznie tworzenie wątków dotyczy wielu rzeczy. Na przykład chodzi o to, aby procesy związane z we / wy były bardziej responsywne (nawet jeśli ogólnie były mniej wydajne), jak niektórzy już powiedzieli. Chodzi także o ułatwienie logiki (ale tylko wtedy, gdy zminimalizujesz stan współdzielenia). Chodzi o wiele rzeczy i musisz zdecydować, czy jego zalety przeważają nad wadami w każdym przypadku z osobna.

TYLKO MOJA poprawna OPINIA
źródło
6

Chociaż z pewnością możesz użyć wątków do przyspieszenia obliczeń w zależności od sprzętu, jednym z ich głównych zastosowań jest robienie więcej niż jednej rzeczy naraz ze względu na łatwość obsługi.

Na przykład, jeśli musisz wykonać pewne przetwarzanie w tle i nadal reagować na dane wejściowe interfejsu użytkownika, możesz użyć wątków. Bez wątków interfejs użytkownika zawieszałby się za każdym razem, gdy próbowano wykonać ciężkie przetwarzanie.

Zobacz także to powiązane pytanie: Praktyczne zastosowania wątków

Krzywka
źródło
Obsługa interfejsu użytkownika to klasyczny przykład zadania związanego z We / Wy. Nie jest dobrze mieć jeden rdzeń procesora obsługujący zarówno zadania przetwarzania, jak i IO.
Donal Fellows
6

Zdecydowanie nie zgadzam się z twierdzeniem @ kyoryu, że idealna liczba to jeden wątek na procesor.

Pomyśl o tym w ten sposób: dlaczego mamy wieloprocesorowe systemy operacyjne? Przez większość historii komputerów prawie wszystkie komputery miały jeden procesor. Jednak od lat sześćdziesiątych wszystkie „prawdziwe” komputery miały wieloprocesorowe (czyli wielozadaniowe) systemy operacyjne.

Uruchamiasz wiele programów, dzięki czemu jeden może działać, podczas gdy inne są blokowane na takie rzeczy, jak IO.

odłóżmy na bok argumenty dotyczące tego, czy wersje systemu Windows przed NT były wielozadaniowe. Od tego czasu każdy prawdziwy system operacyjny miał wielozadaniowość. Niektórzy nie ujawniają go użytkownikom, ale i tak jest tam, robiąc takie rzeczy, jak słuchanie radia w telefonie komórkowym, rozmawianie z chipem GPS, akceptowanie wejścia myszy itp.

Wątki to tylko zadania, które są nieco bardziej wydajne. Nie ma zasadniczej różnicy między zadaniem, procesem i wątkiem.

Procesor to straszna rzecz do marnowania, więc miej wiele rzeczy gotowych do użycia, kiedy tylko możesz.

Zgadzam się, że w przypadku większości języków proceduralnych, C, C ++, Java itp., Napisanie odpowiedniego kodu bezpiecznego dla wątków to dużo pracy. Z 6-rdzeniowymi procesorami dostępnymi obecnie na rynku i 16-rdzeniowymi procesorami w pobliżu, spodziewam się, że ludzie odejdą od tych starych języków, ponieważ wielowątkowość jest coraz bardziej krytycznym wymaganiem.

Niezgoda z @kyoryu to tylko IMHO, reszta to fakt.

fishtoprecords
źródło
5
Jeśli masz wiele wątków związanych z procesorem , idealna liczba to jeden na procesor (lub może jeden mniej, aby zostawić jeden do zarządzania wszystkimi operacjami we / wy, systemem operacyjnym i tym wszystkim). Jeśli masz wątki związane z We / Wy, możesz sporo łączyć na jednym procesorze. Różne aplikacje mają różne kombinacje zadań związanych z procesorem i we / wy; to całkowicie naturalne, ale dlaczego trzeba uważać na uniwersalne deklaracje.
Donal Fellows
1
Oczywiście najważniejszą różnicą między wątkami i procesami jest to, że w systemie Windows nie ma funkcji fork (), więc tworzenie procesów jest naprawdę kosztowne, co prowadzi do nadmiernego wykorzystania wątków.
ninjalj
Z wyjątkiem zwijania białek, SETI itp. Nie ma praktycznych zadań użytkownika, które byłyby związane z obliczeniami przez bardzo długi czas. Zawsze istnieje potrzeba uzyskania informacji od użytkownika, porozmawiania z dyskiem, porozmawianiem z DBMS, itd. Tak, koszt fork () jest jedną z wielu rzeczy, które Cutler przeklął NT, o czym wiedzieli inni w DEC.
fishtoprecords
5

Wyobraź sobie serwer WWW, który musi obsługiwać dowolną liczbę żądań. Musisz obsługiwać żądania równolegle, ponieważ w przeciwnym razie każde nowe żądanie musi czekać, aż wszystkie inne żądania zostaną zakończone (w tym wysłanie odpowiedzi przez Internet). W takim przypadku większość serwerów WWW ma znacznie mniej rdzeni niż liczba żądań, które zwykle obsługują.

Ułatwia to również deweloperowi serwera: wystarczy napisać program wątku, który obsługuje żądanie, nie trzeba myśleć o przechowywaniu wielu żądań, kolejności ich obsługi i tak dalej.

tobiw
źródło
2
Piszesz oprogramowanie dla systemu operacyjnego, który obsługuje wątki, ale nie ma możliwości multipleksowania io? Myślę, że serwer WWW jest prawdopodobnie złym przykładem, ponieważ w tym przypadku multipleksowanie io prawie zawsze będzie bardziej wydajne niż tworzenie większej liczby wątków niż rdzeni.
Jason Coco
3

Wiele wątków będzie uśpionych, czekając na dane wejściowe użytkownika, wejścia / wyjścia i inne zdarzenia.

Szczeniak
źródło
Na pewno. po prostu użyj Menedżera zadań w systemie Windows lub TOP w prawdziwym systemie operacyjnym i zobacz, ile zadań / procesów jest również. Zawsze wynosi 90% lub więcej.
fishtoprecords
2

Wątki mogą pomóc w responsywności w aplikacjach interfejsu użytkownika. Ponadto możesz użyć wątków, aby uzyskać więcej pracy z rdzeni. Na przykład na pojedynczym rdzeniu jeden wątek może wykonywać operacje we / wy, a inny wykonuje obliczenia. Gdyby był jednowątkowy, rdzeń mógłby zasadniczo pozostawać bezczynny, czekając na zakończenie operacji we / wy. To dość wysoki przykład, ale wątki zdecydowanie można wykorzystać do nieco mocniejszego uderzenia w procesor.

Zaraz
źródło
Mówiąc dokładniej, jeden wątek może czekać na operacje we / wy, podczas gdy inny wykonuje obliczenia. Gdyby operacje we / wy wymagały (znacznych) cykli procesora, uruchomienie go w osobnym wątku nie przyniosłoby korzyści. Zaletą jest to, że twój wątek obliczeniowy może działać, podczas gdy twój wątek I / O kręci kciukami, czekając, aż duży aluminiowy cylinder obróci się na miejsce lub pakiety dotrą po kablu z Islandii lub cokolwiek innego.
Ken
2

Procesor lub CPU to fizyczny układ, który jest podłączony do systemu. Procesor może mieć wiele rdzeni (rdzeń jest częścią układu, która jest zdolna do wykonywania instrukcji). Rdzeń może wydawać się systemowi operacyjnemu wiele procesorów wirtualnych, jeśli jest zdolny do jednoczesnego wykonywania wielu wątków (wątek to pojedyncza sekwencja instrukcji).

Proces to inna nazwa aplikacji. Ogólnie procesy są od siebie niezależne. Jeśli jeden proces umiera, nie powoduje to śmierci innego procesu. Procesy mogą się komunikować lub współużytkować zasoby, takie jak pamięć lub we / wy.

Każdy proces ma oddzielną przestrzeń adresową i stos. Proces może zawierać wiele wątków, z których każdy może jednocześnie wykonywać instrukcje. Wszystkie wątki w procesie mają tę samą przestrzeń adresową, ale każdy wątek będzie miał swój własny stos.

Mamy nadzieję, że te definicje i dalsze badania wykorzystujące te podstawy pomogą ci zrozumieć.

Srikar Doddi
źródło
2
W ogóle nie rozumiem, jak to odnosi się do jego pytania. Moja interpretacja jego pytania dotyczy wykorzystania rdzeni wątków i optymalnego wykorzystania dostępnych zasobów lub zachowania wątków w miarę zwiększania ich liczby lub czegoś podobnego.
David
@David być może nie była to bezpośrednia odpowiedź na moje pytanie, ale nadal czuję, że nauczyłem się, czytając ją.
Nick Heiner
1

Idealne użycie wątków to w rzeczywistości jeden na rdzeń.

Jednak jeśli nie używasz wyłącznie asynchronicznych / nieblokujących operacji we / wy, istnieje duża szansa, że ​​w pewnym momencie zostaną zablokowane wątki na we / wy, które nie będą używać procesora.

Ponadto typowe języki programowania utrudniają użycie 1 wątku na procesor. Języki zaprojektowane pod kątem współbieżności (takie jak Erlang) mogą ułatwić nieużywanie dodatkowych wątków.

kyoryu
źródło
Używanie wątków do zadań okresowych jest bardzo powszechnym i pożądanym przepływem pracy i byłoby znacznie mniej niż idealne, gdyby ukradli rdzeń.
Nick Bastin
@Nick Bastin: Tak, ale bardziej wydajne jest umieszczanie tych zadań w kolejce zadań i wykonywanie ich z tej kolejki (lub podobnej strategii). Aby uzyskać optymalną wydajność, 1 wątek na rdzeń bije wszystko, ponieważ zapobiega narzutowi niepotrzebnemu przełączaniu kontekstu i przydzielaniu dodatkowych stosów. Bez względu na wszystko, zadanie okresowe musi ukraść rdzeń, gdy jest `` aktywne '', ponieważ procesor może faktycznie wykonać tylko jedno zadanie na rdzeń (plus takie rzeczy, jak hiperwątkowość, jeśli są dostępne).
kyoryu
@Nick Bastin: Niestety, jak powiedziałem w głównej odpowiedzi, większość współczesnych języków nie nadaje się do łatwego wdrożenia systemu, który robi to skutecznie, nie jest trywialne - w końcu walczysz z typowym użyciem języka.
kyoryu
Nie chodzi mi o to, że jeden wątek na rdzeń nie jest optymalny, chodzi o to, że jeden wątek na rdzeń to marzenie o fajce (chyba że jesteś osadzony), a projektowanie w celu próby uderzenia jest stratą czasu, więc równie dobrze możesz zrób to, co ci to ułatwia (i tak czy inaczej nie jest mniej wydajne w przypadku współczesnego harmonogramu), zamiast próbować zoptymalizować liczbę używanych wątków. Czy powinniśmy rozpinać wątki bez powodu? Oczywiście, że nie, ale to, czy niepotrzebnie marnujesz zasoby komputera, jest problemem niezależnie od wątków.
Nick Bastin
@Nick Bastin: Podsumowując, jeden wątek na rdzeń jest idealny, ale osiągnięcie tego nie jest bardzo prawdopodobne. Prawdopodobnie powinienem był być silniejszy niż „nieco trudny”, kiedy mówiłem o tym, jak prawdopodobne jest osiągnięcie czegoś takiego.
kyoryu
1

Sposób projektowania niektórych interfejsów API sprawia, że nie masz wyboru tylko uruchomić je w osobnym wątku (wszystko z operacjami blokującymi). Przykładem mogą być biblioteki HTTP Pythona (AFAIK).

Zwykle nie stanowi to jednak większego problemu (jeśli jest to problem, system operacyjny lub API powinny być dostarczane z alternatywnym asynchronicznym trybem pracy, tj .:) select(2), ponieważ prawdopodobnie oznacza to, że wątek będzie spał podczas oczekiwania na I / O ukończenie. Z drugiej strony, jeśli coś robi obliczenia ciężki, ty masz go umieścić w osobnym wątku niż powiedzmy, wątek GUI (chyba że lubisz ręcznego Multiplexing).

L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
źródło
1

Wiem, że to bardzo stare pytanie z wieloma dobrymi odpowiedziami, ale jestem tutaj, aby wskazać coś, co jest ważne w obecnym środowisku:

Jeśli chcesz zaprojektować aplikację do obsługi wielu wątków, nie powinieneś projektować pod kątem określonego ustawienia sprzętowego. Technologia procesorów rozwija się dość szybko od lat, a liczba rdzeni stale rośnie. Jeśli celowo projektujesz swoją aplikację tak, aby wykorzystywała tylko 4 wątki, wtedy potencjalnie ograniczasz się do systemu ośmiordzeniowego (na przykład). Obecnie na rynku dostępne są nawet systemy 20-rdzeniowe, więc taka konstrukcja zdecydowanie przynosi więcej szkody niż pożytku.

Jai
źródło
0

W odpowiedzi na Twoje pierwsze przypuszczenie: maszyny wielordzeniowe mogą jednocześnie uruchamiać wiele procesów, a nie tylko wiele wątków pojedynczego procesu.

Odpowiadając na pierwsze pytanie: celem wielu wątków jest zwykle jednoczesne wykonywanie wielu zadań w ramach jednej aplikacji. Klasyczne przykłady w sieci to program pocztowy wysyłający i odbierający pocztę oraz serwer WWW odbierający i wysyłający żądania stron. (Zauważ, że zasadniczo niemożliwe jest zredukowanie systemu takiego jak Windows do uruchamiania tylko jednego wątku lub nawet tylko jednego procesu. Uruchom Menedżera zadań systemu Windows, a zazwyczaj zobaczysz długą listę aktywnych procesów, z których wiele będzie uruchamiać wiele wątków. )

W odpowiedzi na drugie pytanie: większość procesów / wątków nie jest związana z procesorem (tj. Nie działa w sposób ciągły i nieprzerwany), ale zamiast tego często zatrzymuje się i czeka na zakończenie operacji we / wy. Podczas tego oczekiwania inne procesy / wątki mogą działać bez „kradzieży” czekającego kodu (nawet na jednym rdzeniu maszyny).

joe snyder
źródło
-5

Wątek jest abstrakcją, która umożliwia Ci pisanie kodu tak prostego jak sekwencja operacji, błogo nieświadomego, że kod jest wykonywany z przeplotem z innym kodem, zaparkowany w oczekiwaniu na IO lub (może nieco bardziej świadomy) czekając na inne wątki wydarzenia lub wiadomości.

KarlP
źródło
Mógłbym to zmienić, dodając więcej przykładów od czasu głosów przeciw - ale wątek (lub proces, w tym kontekście prawie bez różnicy) nie został wynaleziony w celu zwiększenia wydajności, ale raczej w celu uproszczenia kodu asynchronicznego i uniknięcia pisania skomplikowanych maszyn stanu który musiał obsługiwać wszystkie super-stany możliwe w programie. W rzeczywistości był zwykle jeden procesor, nawet w dużych serwerach. Jestem po prostu ciekawy, dlaczego moja odpowiedź jest uważana za anty-pomocną?
KarlP
-8

Chodzi o to, że ogromna większość programistów nie rozumie, jak zaprojektować maszynę stanową. Możliwość umieszczenia wszystkiego we własnym wątku uwalnia programistę od konieczności zastanawiania się, jak efektywnie przedstawić stan różnych obliczeń w toku, aby można je było przerwać, a następnie wznowić.

Jako przykład rozważ kompresję wideo, zadanie bardzo intensywne dla procesora. Jeśli używasz narzędzia GUI, prawdopodobnie chcesz, aby interfejs pozostawał responsywny (pokazywał postęp, odpowiadał na żądania anulowania, zmianę rozmiaru okna itp.). Dlatego projektujesz oprogramowanie kodera tak, aby przetwarzało dużą jednostkę (jedną lub więcej ramek) naraz i uruchamiało je we własnym wątku, niezależnie od interfejsu użytkownika.

Oczywiście, gdy zdasz sobie sprawę, że byłoby miło móc zapisać stan kodowania w toku, aby móc zamknąć program, aby ponownie uruchomić lub zagrać w grę wymagającą zasobów, zdajesz sobie sprawę, że powinieneś nauczyć się projektować maszyny stanu z początek. Albo to, albo zdecydujesz się zaprojektować zupełnie nowy problem hibernacji procesów w systemie operacyjnym, abyś mógł zawiesić i wznowić poszczególne aplikacje na dysk ...

R .. GitHub PRZESTAŃ POMÓC LODOWI
źródło
7
Nie (całkiem!) Warte -1, ale poważnie, to chyba najbardziej głupia szydercza rzecz, jaką ktoś powiedział na ten temat. Ja na przykład nie mam problemów z implementacją automatu stanowego. Wcale. Po prostu nie lubię ich używać, gdy istnieją inne narzędzia, które pozostawiają jaśniejszy i łatwiejszy w utrzymaniu kod. Maszyny stanowe mają swoje miejsca i tam nie można ich dopasować. Przeplatanie operacji intensywnie wykorzystujących procesor z aktualizacjami GUI nie jest jednym z takich miejsc. Przynajmniej coroutines są tam lepszym wyborem, a gwintowanie jest jeszcze lepsze.
TYLKO MOJA poprawna OPINIA
Dla wszystkich, którzy modyfikują moją odpowiedź, NIE jest to argument przeciwko używaniu wątków! Jeśli potrafisz zakodować maszynę stanów, to świetnie i na pewno często ma sens uruchamianie automatów stanów w oddzielnych wątkach, nawet jeśli nie musisz. Moim komentarzem było to, że często wybór użycia wątków wynika przede wszystkim z chęci uniknięcia projektowania maszyn stanowych, które wielu programistów uważa za „zbyt trudne”, a nie dla jakiejkolwiek innej korzyści.
R .. GitHub PRZESTAŃ POMÓC W LODZIE