Bedste svar
Svaret på spørgsmålet som sagt er: det er det samme som forskellen mellem “en “og” mange “.
Men jeg tror, hvad du sandsynligvis virkelig mente, er noget mere som dette: hvordan adskiller programmeringsmetoder sig for programmering i en enkelt tråd i en enkelt proces sammenlignet med i flere tråde i en enkelt proces?
Der er skrevet bøger om emnet. Men meget kort vedrører forskellene alle én faktor: Når du programmerer i en enkelt tråd og proces, ved du altid, hvordan du kom til den aktuelle instruktion. Instruktioner forekommer i en enkelt rækkefølge. Men når du programmerer til mange tråde, har du ingen idé om, hvilke instruktioner der blev udført i hvilken rækkefølge du skulle komme til den aktuelle instruktion. Dette gør programmering mere kompliceret.
Men der er en anden faktor, der komplicerer det: i modsætning til processer deler tråde hukommelse. Du ved ikke, hvilken tråd sidst har rørt ved en given hukommelsesplacering, eller hvilken der er næste, medmindre du har en slags “synkronisering”. Derfor er det “synkroniserede” nøgleord i Java (revet fra Ada). Skærme, semaforer, låse , betingelsesvariabler og endda meddelelsesoverførsel er alle blevet brugt til synkronisering.
Svar
(Opdatering: Pas på et andet svar, der siger, at du ikke kan have en enkelttrådet webserver, der håndterer samtidige anmodninger godt, fordi det simpelthen ikke er sandt.)
Hvorfor er en multitrådet webserver bedre end en enkelt trådserver? Det er det ikke.
Der er fire grundlæggende måder, hvorpå en webserver kan håndtere samtidighed:
- forking en OS-proces pr. anmodning (som gamle versioner af Apache)
- gydning af en OS-tråd pr. anmodning (som en ny version af Apache)
- ved hjælp af en enkelt trådhændelsesløkke (som nginx )
- ved hjælp af grønne tråde eller lette processer planlagt af en VM-runtime i stedet for OS (som i Erlang)
I øjeblikket er de mest almindelige tilgange nummer 2 og 3.
Der er fordele og ulemper ved begge af dem. For I / O-bundne operationer (en egenskab ved en typisk webserver) får du bedre ydeevne og højere antal samtidige anmodninger når du bruger en hændelsesløkke med en enkelt gevind . Men ulempen er, at du udelukkende skal bruge asynkron ikke-blokerende I / O til alle operationer, ellers blokerer du begivenhedsløbet og mister ydeevne. Af den grund er det lettere at implementere en server med flere tråde, men du betaler i ydeevne.
For CPU-bundne operationer (mindre almindelig for en almindelig webserver, måske mere almindelig for en beregningsintensiv API), er det bedst at have en OS-tråd eller proces pr. kerne . Det er let at gøre med hændelsesløkker med enkelt gevind, fordi du kan køre en klynge med et antal processer en pr. Kerne. Det er svært at gøre med servere med flere tråde, for hvis gydetråde er din eneste måde at håndtere samtidige anmodninger på, kan du ikke rigtig kontrollere, hvor mange tråde du vil have – da du ikke styrer antallet af anmodninger. Når du har flere tråde end antallet af CPU-kerner, mister du ydeevnen til kontekstskifter , og du bruger også meget RAM.
Derfor fungerer en nginx-server med en tråd bedre end en Apache-webserver med flere gevind (og derfor blev nginx oprettet i første omgang). Også Redis , en database, der er kendt for usædvanlig høj ydeevne, er single-threaded .
Et rigtigt eksempel, jeg kan give dig, er dette: Min første webserver var Apache, der kørte på en Linux-maskine med 500 MB RAM. Det forked en ny proces for hver anmodning (den havde faktisk en pool, så der var ikke meget gaffel involveret, men det måtte holde disse processer i live for at genbruge dem og dræbe dem en gang imellem for at undgå ressourceudslip).
Mit operativsystem brugte omkring 100 MB RAM. Hver Apache-proces brugte 20 MB RAM. Det betød, at min server kun kunne håndtere 20 samtidige anmodninger, og der var ingen vej rundt, fordi jeg ikke havde mere RAM. Processerne blev for det meste blokeret på I / O, så CPU-udnyttelsen var meget lav, hver anmodning over de 20 måtte vente, og hvis de 20 var f.eks. længe kørende downloads, så reagerede min server fuldstændigt ikke.
Da nginx-webserveren blev introduceret, brugte den en enkelt-trådet begivenhedssløjfe og blokerede ikke for nogen anmodning. Det kunne håndtere meget flere samtidige anmodninger uden noget problem med det mytiske c10k-problem – nginx blev grundlæggende oprettet for at løse c10k-problemet (10.000 samtidige anmodninger).
Forestil dig, hvor meget RAM der spildes til 10.000 tråde, hvis du kunne endda gyde så mange, og hvor meget tid der bruges til kontekstskiftere.
Hukommelsesbrug af multi-threaded Apache vs single-threaded nginx:
I øvrigt er dette grunden til, at Ryan Dahl brugte en ikke-blokerende I / O og en enkelt-trådet begivenhedssløjfe i Node.js, og han bruger stadig den samme idé i Deno, fordi det er sådan, man skriver netværksservere med høj ydeevne (i modsætning til hvad man måske læser i andre svar her).