Mihin perustuu ohjelelmointikielten nopeustestissä
http://shootout.alioth.debian.org/gp4/benchmark.php?test=threadring&lang=all
muutamien kielten huima nopeus ero esim c-kieleen.
Ilmeisesti tuota testiä ei pystytä edes tekemään kaikilla kielillä.
http://shootout.alioth.debian.org/gp4/benchmark.php?test=threadring&lang=all
muutamien kielten huima nopeus ero esim c-kieleen.
Ilmeisesti tuota testiä ei pystytä edes tekemään kaikilla kielillä.
Vastaukset 4
Vanhimmat
Nopeuserot johtuvat erilaisista säikeistyksen toteutuksista. C-kielellä tehty ohjelma tekee uudet säikeet käyttöjärjestelmän tasolla, joten sen ajaminen aiheuttaa lukuisia järjestelmäkutsuja (Linuxissa clone ja futex). Järjestelmäkutsujen suorittamiseksi prosessori pitää vaihtaa ns. supervisor-tilaan, missä ohjelmakoodi voi käsitellä käyttöjärjestelmän ytimen tietorakenteita. Clone-funktio esimerkiksi luo käyttöjärjestelmän ytimen tietorakenteisiin uuden "prosessin", jolla tosin on tässä tapauksessa on mm. yhteinen muistiavaruus alkuperäisen prosessin (pääohjelman) kanssa. Järjestelmäkutsun jälkeen prosessori palautetaan taas käyttäjätilaan, minkä jälkeen varsinaisen ohjelman suoritus voi taas jatkua. Vaihtaminen supervisor- ja käyttäjätilojen välillä on huomattavasti hitaampaa kuin se, että ohjelma kutsuisi vain omia funktioitaan ja suoritus pysyisi siksi koko ajan käyttäjätilassa.
Joissakin ohjelmointikielissä, esimerkiksi rinnakkaista ohjelmointia vahvasti tukevassa Erlangissa, säikeiden käyttämisestä on haluttu tehdä erittäin halpaa. Tämän takia säikeitä ei ole toteutettukaan käyttöjärjestelmätason otuksina, vaan ne elävät käyttöjärjestelmän näkökulmasta katsottuna saman prosessin sisällä kuin pääohjelmakin. Pelkästään säikeitä käsittelevä Erlang-ohjelma ajetaan lähes koko ajan prosessorin käyttäjätilassa ja on suoritus on siksi merkittävästi tilan vaihtoa vaativia toteutuksia nopeampaa.
"Pelkästään säikeitä käsittelevä Erlang-ohjelma ajetaan lähes koko ajan prosessorin käyttäjätilassa ja on suoritus on siksi merkittävästi tilan vaihtoa vaativia toteutuksia nopeampaa."
Hyvin mielenkiintoista! Mutta nyt kun multicore-rautaa käyttävät sovellukset ovat ihan väistämättä tulossa vakiokäytännöksi ja C on kuitenkin vakiotyökalu, niin onko vanhoja "Concurrent C " -projekteja kaivettu naftaliinista? Kaikki viittaukset tällaisiin kehitelmiin ovat todella vanhoja. En tosiaan usko, että Erlangista tulee vakiotyökalu, vaikka sen käyttö saattaakin yleistyä.
Mitä muita vaihtoehtoja on?
Voi sen tehdä useimmilla, ellei kaikilla shootoutiin osallistuvilla kielillä, jos vain säikeet löytyvät kirjastosta tai kielen toteutuksesta. Ilmeisesti kaikkien kielten kohdalla sitä ei vain vielä ole tehty. Jotkut eivät ota kisailua niin vakavasti, ja jos kieli ei ole erityisen suosittu, ei tekijöitä riitä niin paljon.
Kuten jo sanottiin, testi mittaa tosiaankin sitä, kuinka kallista säikeiden luominen ja käyttäminen on kussakin kielessä. Jos ne on rakennettu kieleen sisään, on tulos varmasti paljon parempi. C-kielihän kehitettiin alun perin koneilla, joissa oli kilotavujen muisti ja yksi hidas prosessori. Ei silloin säikeitä kaivattu.
Ehkä joku C-kielen rinnakkaislaajennnus, kuten Cilk, voisi antaa paljon paremman tuloksen. Lisäksi taitaa olla niin, että mittava osa Erlang-kielestä on toteutettu C-kielellä, joten C kyllä sopivasti käytettynä pystyy hyvään rinnakkaisuuteen; tai paremmin sanottuna, rinnakkaisuuden voi sillä kyllä toteuttaa muullakin tavoin, kuin mitä testin C-ohjelmassa mitataan.
Benchmarkkeja ei kannata ottaa liian vakavasti. Ne eivät edes kerro, minkälaista näitä kieliä on käytännössä käyttää.
Mainitsemasi Cilk vaikutti houkuttelevan yksinkertaiselta. Kokeilinkin toteuttaa sillä shootoutin tehtävän, mutta pian osoittautui, ettei Cilk sovellu tehtävään lainkaan.
Cilk ei tue säikeiden välistä viestintää. Vielä ikävämpää on se, että jos säie odottaa lukkoa, Cilk ajaa sitä busy loopissa kunnes lukko aukeaa. Kirjoittaessani shootout-ohjelmaa Cilkillä oletin sen tietenkin vaihtavan suorituksessa olevaa säiettä, jos yksi säie jää odottamaan lukkoa.
Veikkaan, että 503-prosessorisella (tai sitä isommalla) koneella shootoutin Cilk-ratkaisuni olisi toiminut. Valitettavasti minulla ei ole käytettävissä sellaista konetta ja joulupukkikin ehti jo käydä. Siltä varalta, että joku sai lahjaksi sellaisen, ohessa Cilk-koodi.
#include
#include
#define N 10000000
#define THREADS (503)
static Cilk_lockvar locks[THREADS];
int quit_now = 0;
int n;
cilk void ringthread(int mynum, Cilk_lockvar mylock, Cilk_lockvar nextlock) {
Cilk_lock(mylock);
while (1) {
Cilk_lock(mylock);
if (quit_now == 1) {
Cilk_unlock(nextlock);
return;
}
if (n == 0) {
printf("%d\n", mynum);
quit_now = 1;
Cilk_unlock(nextlock);
return;
}
n -= 1;
Cilk_unlock(nextlock);
}
}
cilk int main(void) {
int i = 0;
n = N;
for (i = 0; i < THREADS; i++) {
Cilk_lock_init(locks[i]);
}
for (i = 0; i < THREADS; i++) {
if (i < THREADS - 1) {
spawn ringthread(i+1, locks[i], locks[i+1]);
} else {
spawn ringthread(i+1, locks[i], locks[0]);
}
}
Cilk_unlock(locks[0]);
sync;
}