Paras vastaus
Vastaus esitettyyn kysymykseen on: se on sama kuin yhden ”ja” monet ”.
Mutta luulen, että luultavasti todella tarkoitit jotain tällaista: miten ohjelmointimenetelmät eroavat ohjelmoinnista yhdessä säikeessä yhdessä prosessissa verrattuna useisiin ketjuihin yhdessä prosessi?
Aiheesta on kirjoitettu kirjoja. Mutta hyvin lyhyesti, erot liittyvät kaikki yhteen tekijään: kun ohjelmoit yhdellä säikeellä ja prosessilla, tiedät aina, kuinka pääset nykyiseen käskyyn. Ohjeet tapahtuvat yhdessä jaksossa. Mutta kun ohjelmoit useita ketjuja, sinulla ei ole aavistustakaan, mitkä ohjeet suoritettiin missä järjestyksessä päästäksesi nykyiseen käskyyn. Tämä tekee ohjelmoinnista monimutkaisemman.
Mutta sitä vaikeuttaa vielä yksi tekijä: toisin kuin prosessit, ketjut jakavat muistia. Et tiedä mikä ketju on viimeksi koskettanut tiettyä muistipaikkaa tai mikä on seuraava, ellei sinulla ole jonkinlaista ”synkronointia”. Siksi ”synkronoitu” avainsana Java-ohjelmassa (poistettu Adasta). Monitorit, semaforit, lukot , ehtomuuttujia ja jopa viestien välitystä on käytetty synkronointiin.
Vastaus
(Päivitys: Varo seuraavaa vastausta, jonka mukaan sinulla ei voi olla yksisäikeistä verkkopalvelinta, joka käsittelee samanaikaisia pyyntöjä hyvin, koska se ei yksinkertaisesti ole totta.)
Miksi monisäikeinen verkkopalvelin on parempi kuin yhden ketjun palvelin? Ei ole.
Verkkopalvelin voi käsitellä samanaikaisuutta neljällä eri tavalla:
- haarautuminen käyttöjärjestelmän prosessi per pyyntö (kuten Apachen vanhat versiot)
- käyttöjärjestelmän ketjun kuteminen per pyyntö (kuten uudet Apache-versiot)
- yksisäikeisen tapahtumasilmukan (kuten nginx) käyttäminen )
- käyttämällä vihreitä säikeitä tai kevyitä prosesseja ajoitettu virtuaalikoneen ajonaikaisesti käyttöjärjestelmän sijaan (kuten Erlangissa)
Tällä hetkellä yleisimmät lähestymistavat ovat numerot 2 ja 3.
Molemmilla on etuja ja haittoja heistä. I / O-sidottuihin toimintoihin (tyypillisen verkkopalvelimen ominaisuus) saat paremman suorituskyvyn ja suurempi samanaikaisten pyyntöjen määrä , kun käytät yksisäikeistä tapahtumasilmukkaa . Mutta haittana on, että sinun on käytettävä yksinomaan asynkronista ei-estävää I / O: ta kaikissa toiminnoissa, muuten estät tapahtumasilmukan ja menetät suorituskyvyn. Tästä syystä monisäikeisen palvelimen toteuttaminen on helpompaa, mutta maksat suorituskyvystä.
Suorittimeen sidotut toiminnot (harvemmin tavallinen verkkopalvelin, ehkä yleisempi laskennallisesti intensiiviselle sovellusliittymälle) on parasta, jos sinulla on yksi käyttöjärjestelmän ketju tai prosessi ydintä kohden . Se on helppo tehdä yksisäikeisillä tapahtumasilmukoilla, koska voit suorittaa joukon prosesseja yhden per ydin. Monisäikeisten palvelimien kanssa on vaikea tehdä, koska jos kutevat säikeet ovat ainoa tapa käsitellä samanaikaisia pyyntöjä, et voi todella hallita, kuinka monta säiettä sinulla on – koska et hallitse pyyntöjen määrää. Kun sinulla on enemmän ketjuja kuin suorittimen ytimien määrä, menetät -kytkinten suorituskyvyn ja käytät myös paljon RAM-muistia.
Siksi yksisäikeinen nginx-palvelin toimii paremmin kuin monisäikeinen Apache-verkkopalvelin (ja siksi nginx luotiin aluksi). Myös Redis , poikkeuksellisen korkean suorituskyvyn omaava tietokanta on yksisäikeinen .
Todellinen esimerkki, jonka voin antaa sinulle, on tämä: Ensimmäinen web-palvelimeni oli Apache, joka toimi Linux-koneella, jossa oli 500 Mt RAM-muistia. Se haaroitti uuden prosessin jokaista pyyntöä varten (sillä oli tosiasiallisesti pooli, joten haarukointia ei ollut paljon, mutta sen oli pidettävä nämä prosessit elossa, jotta niitä voidaan käyttää uudelleen ja tappaa silloin tällöin resurssivuotojen välttämiseksi).
Oma käyttöjärjestelmäni käytti noin 100 Mt RAM-muistia. Jokainen Apache-prosessi käytti 20 Mt RAM-muistia. Se tarkoitti sitä, että palvelimeni pystyi käsittelemään vain 20 samanaikaista pyyntöä, eikä sitä voitu kiertää, koska minulla ei ollut enää RAM-muistia. Prosessit olivat enimmäkseen estetty I / O: lla, joten suorittimen käyttöaste oli hyvin alhainen, jokaisen pyynnön yli 20: n piti odottaa ja jos nämä 20 olivat pitkät lataukset, palvelimeni ei vastannut täysin.
Kun nginx-verkkopalvelin otettiin käyttöön, se käytti yksisäikeistä tapahtumasilmukkaa eikä estänyt pyyntöjä. Se pystyi käsittelemään paljon samanaikaisempia pyyntöjä, eikä sillä ollut ongelmaa myyttisen c10k-ongelman kanssa – nginx luotiin periaatteessa ratkaisemaan c10k-ongelma (10000 samanaikaista pyyntöä).
Kuvittele, kuinka paljon RAM-muistia tuhlataan 10000 säikeelle, jos voisi jopa kutea niin monta ja kuinka paljon aikaa käytetään kontekstikytkimiin.
Monisäikeisen Apache vs. yksisäikeinen nginx-muistin käyttö:
Muuten, tämä on syy, miksi Ryan Dahl käytti ei-estävää I / O- ja yksisäikeistä tapahtumasilmukkaa Node.js: ssä ja hän käyttää edelleen samaa ajatusta Denossa, koska näin kirjoitetaan korkean suorituskyvyn verkkopalvelimia (toisin kuin voit lukea muista vastauksista täältä).