Jaka jest różnica między pojedynczym wątkiem a wieloma wątkami?


Najlepsza odpowiedź

Odpowiedź na postawione pytanie jest taka sama, jak różnica między „jeden „i„ wiele ”.

Myślę jednak, że prawdopodobnie chodziło Ci o coś bardziej podobnego: czym różnią się metodologie programowania w przypadku programowania w pojedynczym wątku w jednym procesie w porównaniu z wieloma wątkami w jednym

Napisano książki na ten temat. Krótko mówiąc, wszystkie różnice dotyczą jednego czynnika: podczas programowania w pojedynczym wątku i procesie zawsze wiesz, jak dotarłeś do bieżącej instrukcji. Instrukcje występują w jednej sekwencji. Ale kiedy programujesz dla wielu wątków, nie masz pojęcia, które instrukcje zostały wykonane w jakiej kolejności, aby dostać się do bieżącej instrukcji. To sprawia, że ​​programowanie jest bardziej skomplikowane.

Ale jest jeszcze jeden czynnik komplikujący to: w przeciwieństwie do procesów, wątki współdzielą pamięć. Nie wiesz, który wątek ostatnio dotknął danego miejsca w pamięci lub który będzie następny, chyba że masz jakąś „synchronizację”. Stąd słowo kluczowe „synchronized” w Javie (wyrwane z Ady). Monitory, semafory, blokady , zmienne warunkowe, a nawet przekazywanie wiadomości zostały użyte do synchronizacji.

Odpowiedź

(Aktualizacja: Uważaj na inną odpowiedź, która mówi, że nie możesz mieć jednowątkowego serwera internetowego, dobrze obsługuje współbieżne żądania, ponieważ to po prostu nieprawda.)

Dlaczego wielowątkowy serwer WWW jest lepszy niż serwer z jednym wątkiem? Tak nie jest.

Istnieją cztery podstawowe sposoby obsługi współbieżności przez serwer WWW:

  1. rozwidlanie proces systemu operacyjnego na żądanie (jak stare wersje Apache)
  2. tworzenie wątku systemu operacyjnego na żądanie (jak nowe wersje Apache)
  3. przy użyciu jednowątkowej pętli zdarzeń (np. nginx )
  4. przy użyciu zielonych wątków lub lekkich procesów zaplanowane przez środowisko wykonawcze maszyny wirtualnej zamiast systemu operacyjnego (jak w Erlangu)

Obecnie najpopularniejsze podejścia to numer 2 i 3.

Obie mają zalety i wady z nich. W przypadku operacji związanych z I / O (charakterystyka typowego serwera WWW) uzyskujesz lepszą wydajność i większa liczba równoczesnych żądań , gdy używasz jednowątkowej pętli zdarzeń . Ale wadą jest to, że musisz używać wyłącznie asynchronicznych nieblokujących operacji we / wy dla wszystkich operacji, w przeciwnym razie zablokujesz pętlę zdarzeń i stracisz wydajność. Z tego powodu łatwiej jest wdrożyć serwer wielowątkowy, ale płacisz za wydajność.

W przypadku operacji związanych z procesorem (rzadziej zwykły serwer WWW, może bardziej typowy dla wymagającego intensywnych obliczeń API) najlepiej mieć jeden wątek systemu operacyjnego lub jeden proces na rdzeń . Jest to łatwe w przypadku jednowątkowych pętli zdarzeń, ponieważ można uruchomić klaster wielu procesów, po jednym na rdzeń. Trudno to zrobić w przypadku serwerów wielowątkowych, ponieważ jeśli tworzenie wątków jest jedynym sposobem obsługi współbieżnych żądań, nie możesz tak naprawdę kontrolować liczby wątków, które będziesz mieć – ponieważ nie kontrolujesz liczby żądań. Gdy masz więcej wątków niż liczba rdzeni procesora, tracisz wydajność dla przełączników kontekstowych , a także zużywasz dużo pamięci RAM.

Dlatego właśnie jednowątkowy serwer nginx działa lepiej niż wielowątkowy serwer WWW Apache (i właśnie dlatego nginx został stworzony w pierwszej kolejności). Ponadto Redis , baza danych znana z wyjątkowo wysokiej wydajności, jest jednowątkowa .

Prawdziwy przykład, który mogę ci podać, jest następujący: moim pierwszym serwerem WWW był Apache działający na komputerze z systemem Linux i 500 MB pamięci RAM. Rozwidlał nowy proces dla każdego żądania (w rzeczywistości miał pulę, więc nie wymagał zbyt wiele rozwidlania, ale musiał utrzymywać te procesy przy życiu, aby je ponownie wykorzystać i zabijać je od czasu do czasu, aby uniknąć wycieku zasobów).

Mój system operacyjny używał około 100 MB pamięci RAM. Każdy proces Apache zużywał 20 MB pamięci RAM. Oznaczało to, że mój serwer mógł obsłużyć tylko 20 jednoczesnych żądań i nie można było tego obejść, ponieważ nie miałem więcej pamięci RAM. Procesy były w większości blokowane na I / O, więc wykorzystanie procesora było bardzo niskie, każde żądanie powyżej tych 20 musiało czekać, a jeśli te 20 było np. długo działające pobieranie, mój serwer zupełnie nie odpowiadał.

Kiedy wprowadzono serwer WWW Nginx, używał on pętli zdarzeń jednowątkowych i nie blokował żadnego żądania. Potrafił obsłużyć znacznie więcej jednoczesnych żądań, nie mając problemu z mitycznym problemem c10k – nginx został zasadniczo stworzony, aby rozwiązać problem c10k (10000 jednoczesnych żądań).

Wyobraź sobie, ile pamięci RAM jest marnowane na 10000 wątków, może nawet pojawić się tak wiele i ile czasu jest używane do przełączania kontekstu.

Wykorzystanie pamięci wielowątkowego Apache kontra jednowątkowy nginx:

Nawiasem mówiąc, to jest powód, dla którego Ryan Dahl użył nieblokującego wejścia / wyjścia i jednowątkowej pętli zdarzeń w Node.js i nadal używa tego samego pomysłu w Deno, ponieważ jest to sposób na zapisywanie wysokowydajnych serwerów sieciowych (w przeciwieństwie do tego, co możesz przeczytać w innych odpowiedziach tutaj).

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *