Beste svaret
Svaret på spørsmålet som sagt er: det er det samme som forskjellen mellom «en «og» mange «.
Men jeg tror det du sannsynligvis egentlig mente er noe mer som dette: hvordan skiller programmeringsmetodikk seg fra programmering i en enkelt tråd i en enkelt prosess sammenlignet med i flere tråder i en enkelt prosess?
Bøker er skrevet om emnet. Men veldig kort, alle forskjellene er knyttet til en faktor: når du programmerer i en enkelt tråd og prosess, vet du alltid hvordan du kom til den gjeldende instruksjonen. Instruksjoner forekommer i en enkelt sekvens. Men når du programmerer for mange tråder, aner du ikke hvilke instruksjoner som ble utført i hvilken rekkefølge du skulle komme til den gjeldende instruksjonen. Dette gjør programmeringen mer komplisert.
Men det er en annen faktor som kompliserer det: i motsetning til prosesser, deler tråder minne. Du vet ikke hvilken tråd som sist berørte en gitt minneplassering, eller hvilken som kommer neste, med mindre du har noen form for «synkronisering». Derav det «synkroniserte» nøkkelordet i Java (revet fra Ada). Skjermer, semaforer, låser , tilstandsvariabler og jevn overføring av meldinger har alle blitt brukt til synkronisering.
Svar
(Oppdater: Se opp for et annet svar som sier at du ikke kan ha en enkelttrådet webserver som håndterer samtidige forespørsler godt fordi det rett og slett ikke stemmer.)
Hvorfor er en flertrådet webserver bedre enn en enkelt trådserver? Det er det ikke.
Det er fire grunnleggende måter hvordan en webserver kan håndtere samtidighet:
- forking en OS-prosess per forespørsel (som gamle versjoner av Apache)
- gyt en OS-tråd per forespørsel (som en ny versjon av Apache)
- ved å bruke en enkelt-trådet hendelsessløyfe (som nginx )
- ved hjelp av grønne tråder eller lette prosesser planlagt av en VM-kjøretid i stedet for operativsystemet (som i Erlang)
For tiden er de vanligste tilnærmingene nummer 2 og 3.
Det er fordeler og ulemper med begge av dem. For I / O-bundne operasjoner (en karakteristikk av en typisk webserver) får du bedre ytelse og høyere antall samtidige forespørsler når du bruker en enkelttrådet hendelsessløyfe . Men ulempen er at du må bruke utelukkende asynkrone ikke-blokkerende I / O for alle operasjoner, ellers vil du blokkere hendelsessløyfen og miste ytelsen. Av den grunn er det lettere å implementere en server med flere tråder, men du betaler i ytelse.
For CPU-bundne operasjoner (mindre vanlig for en vanlig webserver, kanskje mer vanlig for et beregningsintensivt API), er det best å ha en OS-tråd eller prosess per kjerne . Det er enkelt å gjøre med hendelser med en tråd, fordi du kan kjøre en klynge med flere prosesser én per kjerne. Det er vanskelig å gjøre med servere med flere tråder, for hvis gytetråder er den eneste måten å håndtere samtidige forespørsler på, kan du ikke kontrollere hvor mange tråder du vil ha – siden du ikke kontrollerer antall forespørsler. Når du har flere tråder enn antall CPU-kjerner, mister du ytelsen for kontekstbrytere , og du bruker også mye RAM.
Det er grunnen til at en nginx-server med en tråd klarer seg bedre enn en Apache-webserver med flere tråder (og det er derfor nginx ble opprettet i utgangspunktet). Også Redis , en database som er kjent for eksepsjonelt høy ytelse, er enkelttrådet .
Et reelt eksempel jeg kan gi deg er dette: Min første webserver var Apache som kjørte på en Linux-maskin med 500 MB RAM. Det forked en ny prosess for hver forespørsel (den hadde faktisk et basseng, så det var ikke mye gaffel involvert, men det måtte holde disse prosessene i live for å gjenbruke dem og drepe dem en gang i blant for å unngå ressurslekkasje). p> Operativsystemet mitt brukte rundt 100 MB RAM. Hver Apache-prosess brukte 20 MB RAM. Det betydde at serveren min bare kunne håndtere 20 samtidige forespørsler, og det var ingen vei rundt det fordi jeg ikke hadde mer RAM. Prosessene ble for det meste blokkert på I / O, så CPU-bruken var veldig lav, hver forespørsel over de 20 måtte vente, og hvis de 20 var f.eks. langvarige nedlastinger da serveren min ikke reagerte.
Da nginx webserver ble introdusert, brukte den en enkelt tråds hendelsessløyfe og blokkerte ikke for noen forespørsel. Den kunne håndtere mye flere samtidige forespørsler uten å ha noe problem med det mytiske c10k-problemet – nginx ble i utgangspunktet opprettet for å løse c10k-problemet (10 000 samtidige forespørsler).
Tenk deg hvor mye RAM som er bortkastet for 10.000 tråder hvis du kunne til og med gyte så mange og hvor mye tid som brukes til kontekstbrytere.
Minnebruk av multi-threaded Apache vs single-threaded nginx:
Dette er forøvrig grunnen til at Ryan Dahl brukte en ikke-blokkerende I / O og en enkelttrådet hendelsessløyfe i Node.js, og han bruker fortsatt den samme ideen i Deno, fordi det er slik du kan skrive nettverksservere med høy ytelse (i motsetning til hva du kan lese i andre svar her).