Bästa svaret
Svaret på frågan som uttryckt är: det är samma som skillnaden mellan ”en ”och” många ”.
Men jag tror att det du förmodligen egentligen menade är något mer så här: hur skiljer sig programmeringsmetoderna för programmering i en enda tråd i en enda process jämfört med i flera trådar i en enda process?
Böcker har skrivits om ämnet. Men mycket kort, skillnaderna är alla relaterade till en faktor: när du programmerar i en enda tråd och process vet du alltid hur du kom till den aktuella instruktionen. Instruktioner förekommer i en enda sekvens. Men när du programmerar för många trådar har du ingen aning om vilka instruktioner som utfördes i vilken ordning du ska komma till den aktuella instruktionen. Detta gör programmeringen mer komplicerad.
Men det finns en annan faktor som komplicerar den: till skillnad från processer delar trådar minne. Du vet inte vilken tråd som senast rörde vid en viss minnesplats, eller vilken som kommer nästa, såvida du inte har någon form av ”synkronisering”. Därav ”synkroniserade” nyckelordet i Java (rippat från Ada). Bildskärmar, semaforer, lås , villkorsvariabler och till och med meddelandeöverföring har alla använts för synkronisering.
Svar
(Uppdatering: Se upp för ett annat svar som säger att du inte kan ha en enda tråd webbserver som hanterar samtidiga förfrågningar bra eftersom det helt enkelt inte är sant.)
Varför är en flertrådad webbserver bättre än en enda trådserver? Det är det inte.
Det finns fyra grundläggande sätt för hur en webbserver kan hantera samtidighet:
- forking en OS-process per förfrågan (som gamla versioner av Apache)
- spawning en OS-tråd per begäran (som en ny version av Apache)
- med hjälp av en enda gängad händelsesslinga (som nginx )
- med gröna trådar eller lätta processer schemalagd med en VM-körning istället för operativsystemet (som i Erlang)
För närvarande är de vanligaste metoderna nummer 2 och 3.
Det finns fördelar och nackdelar med båda av dem. För I / O-bundna operationer (en egenskap hos en typisk webbserver) får du bättre prestanda och högre antal samtidiga förfrågningar när du använder en entrådig händelsesslinga . Men nackdelen är att du behöver använda uteslutande asynkron Icke-blockerande I / O för alla operationer eller annars blockerar du händelsens loop och förlorar prestanda. Av den anledningen är det lättare att implementera en server med flera trådar men du betalar i prestanda.
För CPU-bundna operationer (mindre vanligt för en vanlig webbserver, kanske vanligare för ett beräkningsintensivt API) är det bäst att ha en OS-tråd eller process per kärna . Det är lätt att göra med händelsesslingor med en tråd eftersom du kan köra ett kluster med ett antal processer en per kärna. Det är svårt att göra med servrar med flera trådar, för om lektrådar är ditt enda sätt att hantera samtidiga förfrågningar så kan du inte riktigt styra hur många trådar du kommer att ha – eftersom du inte kontrollerar antalet förfrågningar. När du har fler trådar än antalet CPU-kärnor tappar du prestanda för kontextväxlar och du använder också mycket RAM.
Det är därför en enkel trådad nginx-server presterar bättre än en Apache-webbserver med flera trådar (och det var därför nginx skapades i första hand). Även Redis , en databas som är känd för exceptionellt höga prestanda är enkelgängad .
Ett riktigt exempel jag kan ge dig är detta: Min första webbserver var Apache som kördes på en Linux-maskin med 500 MB RAM. Det gafflade en ny process för varje förfrågan (den hade faktiskt en pool så det var inte mycket gafflar involverade men det var tvungen att hålla dessa processer vid liv för att återanvända dem och döda dem då och då för att undvika resursläckage).
Mitt operativsystem använde cirka 100 MB RAM-minne. Varje Apache-process använde 20 MB RAM. Det innebar att min server bara kunde hantera 20 samtidiga förfrågningar och det fanns ingen väg runt det eftersom jag inte hade mer RAM. Processerna blockerades mestadels på I / O så CPU-utnyttjandet var väldigt lågt, varje begäran över de 20 fick vänta och om de 20 var t.ex. länge nedladdningar svarade inte min server helt.
När nginx-webbservern introducerades använde den en enda trådhändelsesslinga och blockerade inte för någon begäran. Det kunde hantera mycket fler samtidiga förfrågningar utan problem med det mytiska c10k-problemet – nginx skapades i grunden för att lösa c10k-problemet (10 000 samtidiga förfrågningar).
Tänk dig hur mycket RAM som går till spillo för 10 000 trådar om du kan till och med leka så många och hur mycket tid som används för kontextväxlare.
Minnesanvändning av flertrådad Apache vs entrådig nginx:
För övrigt är det anledningen till att Ryan Dahl använde en icke-blockerande I / O och en entrådad händelsesslinga i Node.js och han använder fortfarande samma idé i Deno, eftersom det är så att man skriver högpresterande nätverksservrar (i motsats till vad du kan läsa i andra svar här).