Ostatnio słyszałem, jak kilka osób mówi, że w Linuksie prawie zawsze lepiej jest używać procesów zamiast wątków, ponieważ Linux jest bardzo wydajny w przetwarzaniu procesów i ponieważ istnieje wiele problemów (takich jak blokowanie) związanych z wątkami. Jestem jednak podejrzliwy, ponieważ wydaje się, że wątki mogą dać całkiem duży wzrost wydajności w niektórych sytuacjach.
Więc moje pytanie brzmi: w obliczu sytuacji, w której wątki i procesy mogłyby całkiem dobrze sobie poradzić, czy powinienem używać procesów lub wątków? Na przykład, jeśli piszę serwer WWW, czy powinienem używać procesów lub wątków (lub kombinacji)?
linux
performance
multithreading
process
użytkownik17918
źródło
źródło
Odpowiedzi:
Linux używa modelu wątków 1-1, bez (do jądra) bez rozróżnienia między procesami i wątkami - wszystko jest po prostu zadaniem wykonalnym. *
W Linuksie wywołanie systemowe
clone
klonuje zadanie z konfigurowalnym poziomem udostępniania, między innymi:CLONE_FILES
: udostępnij tę samą tabelę deskryptorów plików (zamiast tworzyć kopię)CLONE_PARENT
: nie konfiguruj relacji rodzic-dziecko między nowym zadaniem a starym (w przeciwnym razie childgetppid()
= rodzicgetpid()
)CLONE_VM
: udostępnij to samo miejsce w pamięci (zamiast tworzyć kopię COW )fork()
Połączeniaclone(
najmniej dzielą się,)
apthread_create()
połączeniaclone(
dzielą najwięcej)
. **fork
ing kosztuje nieco więcej niżpthread_create
ing z powodu kopiowania tabel i tworzenia mapowań COW dla pamięci, ale programiści jądra Linuksa próbowali (i udało się) zminimalizować te koszty.Przełączanie między zadaniami, jeśli współużytkują tę samą przestrzeń pamięci i różne tabele, będzie nieco tańsze niż w przypadku, gdy nie zostaną one udostępnione, ponieważ dane mogą być już załadowane do pamięci podręcznej. Jednak przełączanie zadań jest nadal bardzo szybkie, nawet jeśli nic nie jest współużytkowane - jest to coś, co programiści jądra Linuksa starają się zapewnić (i zapewnić to).
W rzeczywistości, jeśli jesteś w systemie multi-procesora, nie dzielenie może faktycznie być korzystne dla wydajności: jeśli każde zadanie jest uruchomiony na innym procesorze, synchronizacja pamięci współdzielonej jest drogie.
* Uproszczony.
CLONE_THREAD
powoduje, że dostarczanie sygnałów jest współużytkowane (co wymagaCLONE_SIGHAND
, co dzieli tabelę obsługi sygnałów).** Uproszczony. Istnieją zarówno
SYS_fork
iSYS_clone
wywołań systemowych, ale w jądrze,sys_fork
isys_clone
są bardzo cienkie obwolut wokół tej samejdo_fork
funkcji, która sama jest cienka otoki wokółcopy_process
. Tak, terminyprocess
,thread
itask
są używane zamiennie raczej w jądrze Linuksa ...źródło
socket
,bind
,listen
,fork
, a następnie mieć wiele procesówaccept
połączeń w tym samym gnieździe odsłuchu. Proces może przestać akceptować, jeśli jest zajęty, a jądro przekieruje połączenia przychodzące do innego procesu (jeśli nikt nie nasłuchuje, jądro będzie kolejkować lub upuszczać, w zależności odlisten
zaległości). Nie masz dużo większej kontroli nad podziałem pracy, ale zwykle to wystarczy!clone()
określić, które zasoby są udostępniane. Zadanie może równieżunshare()
zawierać zasoby w dowolnym późniejszym czasie.task_struct
zadanie dla każdego. Jest to często nazywane „procesem” w całym kodzie jądra, ale odpowiada każdemu uruchamialnemu wątkowi. Nie maprocess_struct
; jeśli kilkatask_struct
s jest połączonych ze sobą przez ichthread_group
listę, to są one tym samym „procesem” do przestrzeni użytkownika. Jest trochę specjalnej obsługi „wątków”, np. Wszystkie wątki rodzeństwa są zatrzymywane na fork i exec i pojawia się tylko wątek „główny”ls /proc
. Każdy wątek jest dostępny za pośrednictwem/proc/pid
, niezależnie od tego, czy jest wymieniony na liście,/proc
czy nie.clone(CLONE_THREAD | CLONE_VM | CLONE_SIGHAND))
dałby ci nowy „wątek”, który nie udostępnia katalogu roboczego, plików lub blokad, a jednocześnieclone(CLONE_FILES | CLONE_FS | CLONE_IO)
„proces”, który to robi. Podstawowy system tworzy zadania poprzez klonowanie;fork()
ipthread_create()
są tylko funkcjami bibliotecznymi, które wywołująclone()
inaczej (jak napisałem w tej odpowiedzi).Linux (a nawet Unix) daje trzecią opcję.
Opcja 1 - procesy
Utwórz samodzielny plik wykonywalny, który obsługuje część (lub wszystkie części) aplikacji, i wywołaj ją osobno dla każdego procesu, np. Program uruchamia swoje kopie w celu delegowania zadań.
Opcja 2 - wątki
Utwórz autonomiczny plik wykonywalny, który uruchamia się z jednym wątkiem i utwórz dodatkowe wątki do wykonania niektórych zadań
Opcja 3 - widelec
Dostępne tylko w systemie Linux / Unix, jest to nieco inne. Rozwidlony proces jest tak naprawdę własnym procesem z własną przestrzenią adresową - dziecko nie może (normalnie) wpłynąć na przestrzeń adresową rodzica lub rodzeństwa (w przeciwieństwie do wątku) - dzięki czemu zyskujesz większą niezawodność.
Jednak strony pamięci nie są kopiowane, są one kopiowane przy zapisie, więc zwykle używa się mniej pamięci, niż można sobie wyobrazić.
Rozważ program serwera WWW, który składa się z dwóch kroków:
Jeśli użyłeś wątków, krok 1 zostałby wykonany raz, a krok 2 w wielu wątkach. Jeśli używałeś „tradycyjnych” procesów, kroki 1 i 2 musiałyby zostać powtórzone dla każdego procesu, a pamięć do przechowywania konfiguracji i danych wykonawczych powielona. Jeśli użyłeś fork (), możesz zrobić krok 1 raz, a następnie fork (), pozostawiając dane środowiska wykonawczego i konfigurację w pamięci, bez zmian, bez kopiowania.
Istnieją więc naprawdę trzy opcje.
źródło
To zależy od wielu czynników. Procesy są ważniejsze niż wątki i mają wyższy koszt uruchomienia i zamknięcia. Komunikacja międzyprocesowa (IPC) jest również trudniejsza i wolniejsza niż komunikacja między wątkami.
I odwrotnie, procesy są bezpieczniejsze i bardziej bezpieczne niż wątki, ponieważ każdy proces działa we własnej wirtualnej przestrzeni adresowej. Jeśli jeden proces ulega awarii lub przepełnienie bufora, w ogóle nie wpływa na żaden inny proces, podczas gdy wątek ulega awarii, usuwa wszystkie pozostałe wątki w procesie, a jeśli wątek ma przepełnienie bufora, otwiera się dziura bezpieczeństwa we wszystkich wątkach.
Tak więc, jeśli moduły aplikacji mogą działać głównie niezależnie przy niewielkiej komunikacji, prawdopodobnie powinieneś użyć procesów, jeśli możesz sobie pozwolić na koszty uruchomienia i zamknięcia. Wydajność IPC będzie minimalna, a Ty będziesz nieco bezpieczniejszy przed błędami i dziurami w zabezpieczeniach. Jeśli potrzebujesz każdej wydajności, którą możesz uzyskać lub mieć dużo wspólnych danych (takich jak złożone struktury danych), idź z wątkami.
źródło
Inni omawiali te względy.
Być może istotną różnicą jest to, że w systemie Windows procesy są ciężkie i kosztowne w porównaniu do wątków, aw Linuksie różnica jest znacznie mniejsza, więc równanie równoważy się w innym punkcie.
źródło
Dawno, dawno temu istniał Unix, a w tym starym, dobrym Unixie było mnóstwo narzutów związanych z procesami, więc niektórzy sprytni ludzie zrobili tworzenie wątków, które będą miały tę samą przestrzeń adresową z procesem nadrzędnym i potrzebowali jedynie zredukowanego kontekstu przełącznik, dzięki czemu zmiana kontekstu byłaby bardziej wydajna.
We współczesnym Linuksie (2.6.x) wydajność przełączania kontekstu procesu nie różni się znacznie od wątku (tylko wątek MMU jest dodatkowy dla wątku). Występuje problem ze wspólną przestrzenią adresową, co oznacza, że wadliwy wskaźnik w wątku może uszkodzić pamięć procesu nadrzędnego lub innego wątku w tej samej przestrzeni adresowej.
Proces jest chroniony przez MMU, więc wadliwy wskaźnik spowoduje tylko sygnał 11 i nie spowoduje uszkodzenia.
Zasadniczo używałbym procesów (niewiele obciążeń związanych z przełączaniem kontekstu w Linuksie, ale ochrona pamięci z powodu MMU), ale pthreads, gdybym potrzebował klasy harmonogramu w czasie rzeczywistym, która razem jest inną filiżanką herbaty.
Jak myślisz, dlaczego wątki mają tak duży wzrost wydajności w systemie Linux? Czy masz na to jakieś dane, czy to tylko mit?
źródło
Jak ściśle powiązane są twoje zadania?
Jeśli mogą żyć niezależnie od siebie, użyj procesów. Jeśli polegają na sobie, użyj wątków. W ten sposób możesz zabić i zrestartować zły proces bez zakłócania działania innych zadań.
źródło
Aby jeszcze bardziej skomplikować sprawy, istnieje coś takiego jak pamięć lokalna wątków i pamięć współdzielona Unix.
Lokalne przechowywanie wątków pozwala, aby każdy wątek miał osobne wystąpienie obiektów globalnych. Użyłem go tylko podczas tworzenia środowiska emulacji na systemie Linux / Windows dla kodu aplikacji działającego w systemie RTOS. W RTOS każde zadanie było procesem z własną przestrzenią adresową, w środowisku emulacji każde zadanie było wątkiem (ze wspólną przestrzenią adresową). Używając TLS do takich rzeczy jak singletony, byliśmy w stanie mieć osobną instancję dla każdego wątku, tak jak w „prawdziwym” środowisku RTOS.
Pamięć współdzielona może (oczywiście) przynieść korzyści w zakresie wydajności związane z dostępem wielu procesów do tej samej pamięci, ale kosztem / ryzykiem związanym z koniecznością prawidłowej synchronizacji procesów. Jednym ze sposobów na to jest utworzenie przez jeden proces struktury danych we wspólnej pamięci, a następnie wysłanie uchwytu do tej struktury poprzez tradycyjną komunikację między procesami (jak nazwany potok).
źródło
W mojej ostatniej pracy z LINUX należy pamiętać o bibliotekach. Jeśli używasz wątków, upewnij się, że wszystkie biblioteki, których możesz używać w wątkach, są bezpieczne dla wątków. To mnie piekło kilka razy. W szczególności libxml2 nie jest fabrycznie bezpieczny dla wątków. Można go skompilować z wątkiem bezpiecznym, ale to nie to, co otrzymujesz dzięki aptitude install.
źródło
Musiałbym się zgodzić z tym, co słyszeliście. Kiedy porównujemy nasz klaster (
xhpl
i takie), zawsze uzyskujemy znacznie lepszą wydajność dzięki procesom nad wątkami.</anecdote>
źródło
Decyzja między wątkiem / procesem zależy trochę od tego, do czego będziesz go używać. Jedną z zalet tego procesu jest to, że ma PID i może zostać zabity bez zakończenia rodzica.
Na przykład serwera WWW w świecie rzeczywistym apache 1.3 służył tylko do obsługi wielu procesów, ale w wersji 2.0 dodano abstrakcję, dzięki czemu można przełączać się między nimi. Komentarze wydają się zgadzać, że procesy są bardziej niezawodne, ale wątki mogą dać nieco lepszą wydajność (z wyjątkiem okien, w których wydajność procesów jest do bani i chcesz używać tylko wątków).
źródło
W większości przypadków wolę procesy niż wątki. wątki mogą być przydatne, gdy masz stosunkowo mniejsze zadanie (narzut procesu >> czas zajęty przez każdą podzieloną jednostkę zadania) i istnieje potrzeba dzielenia pamięci między nimi. Pomyśl o dużej tablicy. Również (offtopic), zauważ, że jeśli twoje wykorzystanie procesora wynosi 100 procent lub jest blisko niego, nie będzie żadnych korzyści z wielowątkowości lub przetwarzania. (w rzeczywistości pogorszy się)
źródło
Wątki -> Wątki dzielą przestrzeń pamięci, są abstrakcją procesora, są lekkie. Procesy -> Procesy mają własną przestrzeń pamięci, jest to abstrakcja komputera. Aby wykonać zadanie równoległe, musisz wyodrębnić procesor. Zaletą stosowania procesu nad wątkiem jest jednak bezpieczeństwo, stabilność, podczas gdy wątek zużywa mniej pamięci niż proces i oferuje mniejsze opóźnienia. Przykładem sieciowym jest Chrome i Firefox. W przypadku Chrome każda karta jest nowym procesem, dlatego użycie pamięci chrome jest wyższe niż firefox, a zapewnione bezpieczeństwo i stabilność jest lepsze niż firefox. Bezpieczeństwo zapewniane przez chrome jest lepsze, ponieważ każda zakładka jest nowym procesem, inna zakładka nie może wtargnąć w przestrzeń pamięci danego procesu.
źródło
Myślę, że wszyscy wykonali świetną robotę odpowiadając na twoje pytanie. Właśnie dodam więcej informacji o wątku w porównaniu do procesu w systemie Linux, aby wyjaśnić i podsumować niektóre poprzednie odpowiedzi w kontekście jądra. Tak więc moja odpowiedź dotyczy kodu specyficznego dla jądra w systemie Linux. Zgodnie z dokumentacją jądra systemu Linux nie ma wyraźnego rozróżnienia między wątkiem a procesem, z wyjątkiem tego, że wątek używa wspólnej wirtualnej przestrzeni adresowej w przeciwieństwie do procesu. Zauważ też, że jądro Linux używa terminu „zadanie” w odniesieniu do procesu i wątku w ogóle.
„Brak wewnętrznych struktur implementujących procesy lub wątki, zamiast tego istnieje struktura task_struct, która opisuje abstrakcyjną jednostkę planowania o nazwie task”
Również według Linusa Torvaldsa NIE powinieneś w ogóle myśleć o procesie kontra wątek, a ponieważ jest on zbyt ograniczający, a jedyną różnicą jest COE lub kontekst wykonania w kategoriach „oddziel przestrzeń adresową od obiektu nadrzędnego” lub wspólną przestrzeń adresową. W rzeczywistości używa on przykładem serwera WWW, aby jego punkt tutaj (który bardzo polecam czytanie).
Pełny kredyt na dokumentację jądra systemu Linux
źródło
Jeśli chcesz współdzielić zasoby, naprawdę powinieneś używać wątków.
Weź również pod uwagę fakt, że przełączanie kontekstu między wątkami jest znacznie tańsze niż przełączanie kontekstu między procesami.
Nie widzę powodu, aby jawnie stosować osobne procesy, chyba że masz ku temu dobry powód (bezpieczeństwo, sprawdzone testy wydajności itp.)
źródło