Vilka programmeringsspråk använder minst elektricitet?
Kan data om energianvändning berätta något om kvaliteten på våra programmeringsspråk?
Förra året bestämde sig ett team av sex forskare i Portugal från tre olika universitet för att undersöka den här frågan och publicerade till slut en artikel med titeln ”Energy Efficiency Across Programming Languages”. De körde lösningarna till 10 programmeringsproblem skrivna på 27 olika språk, samtidigt som de noggrant övervakade hur mycket el varje problem använde – samt dess hastighet och minnesanvändning.
Specifikt använde de 10 problem från Computer Language Benchmarks Game, ett gratisprogramvaruprojekt för att jämföra prestanda som innehåller en standarduppsättning av enkla algoritmiska problem, samt en ram för att köra tester. (Det var tidigare känt som ”The Great Computer Language Shootout”.) ”Detta gjorde det möjligt för oss att få en jämförbar, representativ och omfattande uppsättning program… tillsammans med kompilerings-/utföraralternativ och kompilatorversioner.”
Det var viktigt att köra en mängd olika benchmark-tester eftersom resultaten i slutändan varierade beroende på vilket test som utfördes. Till exempel visade sig överlag språket C vara det snabbaste och även det mest energieffektiva språket. Men i det benchmarktest som gick ut på att skanna en DNA-databas efter en viss genetisk sekvens var Rust det mest energieffektiva – medan C kom på tredje plats.
Men även inom samma test beror det ”bästa” språket på vad ditt kriterium är. För det testet visade sig C också bara vara det näst snabbaste språket (återigen bakom Rust). Men Rust tappade hela nio placeringar om resultaten sorterades efter minnesanvändning. Och även om Fortran var det näst mest energieffektiva språket för detta test, tappade det också hela sex placeringar när resultaten istället sorterades efter exekveringstid.
Ett snabbare språk är inte alltid det mest energieffektiva.
Forskarna noterar att de ”strikt följde” CLBG-projektets riktlinjer om kompilatorversioner och de bästa optimeringsflaggorna. Energiförbrukningen mättes med hjälp av ett verktyg från Intel – verktyget Running Average Power Limit – där varje program exekverades inte bara en gång utan tio gånger, ”för att minska påverkan från kallstarter och cache-effekter och för att kunna analysera mätningarnas konsistens och undvika outliers”. (Av denna anledning rapporterar de att ”de uppmätta resultaten är ganska konsekventa.”) För ökad konsistens gjordes alla tester på en stationär dator som körde Linux Ubuntu Server 16.10 (kärnversion 4.8.0-22-generic), med 16 GB RAM och en 3,20 GHz Haswell Intel Core i5-4460-processor.
I sitt dokument nämner forskarna några intressanta resultat.
”Lisp, on average, consumes 2.27x mer energi (131,34J) än C, samtidigt som det tar 2,44x mer tid att utföra (4926,99ms) och 1,92x mer minne (126,64Mb) behövs jämfört med Pascal.”
De jämförde också resultaten från kompilerade språk jämfört med tolkade språk (med en separat kategori för språk som körs på virtuella maskiner). Och dokumentet innehåller också en separat jämförelse av de olika programmeringsparadigmen – inklusive både funktionell och imperativ programmering, plus objektorienterad programmering och skriptning.
Is Faster Greener?
Dokumentet tog en hård titt på det vanliga antagandet att ett snabbare program alltid kommer att förbruka mindre energi, och påpekade att det inte är så enkelt som den fysikaliska lagen som säger att E(nergy) = T(ime) x P(ower). Detta beror delvis på att energin inte förbrukas i en jämn takt, konstaterar forskarna och menar att detta kan påverka andra forskares arbete med att undersöka om ett programs körtid påverkar dess energiförbrukning. (”Slutsatser om denna fråga divergerar ibland…”) I ett av deras benchmark-tester tog ett Chapel-program 55 procent mindre tid att utföra än ett motsvarande program skrivet i Pascal – och ändå förbrukade det Pascal-programmet 10 procent mindre energi.
Så även om det fortfarande finns en allmän uppfattning att energiförbrukningen minskar när programmen körs snabbare, konstaterar forskarna entydigt att ”ett snabbare språk är inte alltid det mest energieffektiva”
Det kan vara en svår fråga att besvara, eftersom energiförbrukningen påverkas av många faktorer (bland annat kvaliteten på kompilatorn och vilka bibliotek som används). Men i slutändan kunde forskarna till och med dela upp energiförbrukningen utifrån om den förbrukades av CPU:n eller DRAM – och drog slutsatsen att majoriteten av strömmen (cirka 88 procent) i genomsnitt förbrukades av CPU:n, oavsett om referensprogrammet var kompilerat, tolkat eller kördes på en virtuell maskin.
Interessant nog uppvisade tolkade språk en något högre variation, där CPU:n ibland förbrukade så mycket som 92.90 procent av strömmen eller så lite som 81,57 procent.
Efter att ha studerat sina resultat drog forskarna också slutsatsen att förhållandet mellan toppanvändning av DRAM och energiförbrukning ”är nästan obefintligt”.
Forskningen ger några fler insikter i den eviga frågan: är snabbare grönare? Ja, det är sant att ”de fem mest energieffektiva språken behåller sin plats när de sorteras efter exekveringstid och med mycket små skillnader i både energi- och tidsvärden.”
För nio av tio benchmarkproblem kom faktiskt den bästa poängen (både när det gäller snabbhet och energieffektivitet) från ett av de tre snabbaste och mest energieffektiva språken totalt sett – vilket inte förvånade forskarna. ”Det är allmänt känt att dessa tre främsta språk (C, C++ och Rust) är kända för att vara kraftigt optimerade och effektiva när det gäller exekveringsprestanda, vilket våra data också visar.”
Men man ser inte samma ordning när man rangordnar de övriga 24 språken efter körtid som när man rangordnar dem efter energieffektivitet. ”Endast fyra språk behåller samma energi- och tidsranking (OCaml, Haskel, Racket och Python), medan resten är helt omblandade.”
Och till och med på enskilda benchmarktester finns det fall där snabbt presterande språk inte är de mest energieffektiva.
Fördelarna med kompilerade språk
Det fanns andra intressanta resultat. Kompilerade språk ”tenderar att vara” de mest energieffektiva och snabbast fungerande – och deras artikel kan till och med kvantifiera denna skillnad med en siffra. ”I genomsnitt förbrukade kompilerade språk 120 J för att utföra lösningarna, medan detta värde för en virtuell maskin och tolkade språk var 576 J respektive 2365 J.”
Forskarna tillämpade också samma precision när de jämförde exekveringstiderna och drog slutsatsen att i genomsnitt tog ”kompilerade språk 5103 ms, virtuella maskins språk 20623 ms och tolkade språk 87614 ms.”
Av de fem bästa språken i båda kategorierna var fyra av dem kompilerade. (Undantaget är Java.)
Energiförbrukning | Run-tid | |
C | 57J | 2019 ms |
Rust | 59J | 2103 ms |
C++ | 77J | 3155 ms |
Ada | 98J | 3740 ms |
Java | 114J | 3821 ms |
De fem långsammaste språken var alla tolkade: Lua, Python, Perl, Ruby och Typescript. Och de fem språk som förbrukade mest energi var också tolkade: Perl, Python, Ruby, JRuby och Lua.
Men samtidigt, när strängar manipuleras med reguljära uttryck, visar sig tre av de fem mest energieffektiva språken vara tolkade språk (TypeScript, JavaScript och PHP), ”även om de tenderar att inte vara särskilt energieffektiva i andra scenarier”.
Kompilerade språk intog också de fem första platserna när det gällde minsta mängden minnesutrymme som användes.
Språk | Minnesutrymme behövs |
Pascal | 66Mb |
Go | 69Mb |
C | 77Mb |
Fortran | 82Mb |
C++ | 88Mb |
”I genomsnitt, de kompilerade språken 125 Mb, de virtuella maskinspråken 285 Mb och de tolkade 426 Mb”, rapporterar forskarna. Samtidigt tog de tolkade språken fyra av de fem nedersta platserna i anspråk, vilket innebär att de förbrukade mest minnesutrymme: JRuby, Dart, Lua och Perl. (Även om Erlang inte är ett tolkat språk skulle det också hamna bland de fem nedersta, mellan Dart och Lua).
”Om man sorterar efter programmeringsparadigm behövde de imperativa språken 116 Mb, de objektorienterade 249 Mb, de funktionella 251 Mb och slutligen skriptspråken 421 Mb.”
I själva verket var det så att när man jämförde de olika paradigmen så var det ofta den imperativa programmeringen som var bäst. Dess referensprogram använde också i genomsnitt mycket mindre energi – och sprang mycket snabbare – än referensprogrammen för objektorienterade, funktionella och skriptparadigmen.
Energiförbrukning | Körningstid | |
Imperativ | 125J | 5585ms |
Objekt-Oriented | 879J | 32965ms |
Functional | 1367J | 42740ms |
Scripting | 2320J | 88322 ms |
Men det finns många faktorer att ta hänsyn till. ”Det är tydligt att olika programmeringsparadigm och till och med språk inom samma paradigm har helt olika inverkan på energiförbrukning, tid och minne”, skriver forskarna. Men vilken av dessa som är viktigast beror på ditt scenario. (Bakgrundsuppgifter behöver till exempel inte alltid den snabbaste körtiden…)
Och vissa tillämpningar kräver att man tar hänsyn till två faktorer – till exempel energiförbrukning och exekveringstid. I det fallet är ”C den bästa lösningen, eftersom den är dominerande för båda de enskilda målen”, skriver forskarna. Om du försöker spara tid samtidigt som du använder mindre minne är C, Pascal och Go ”likvärdiga” – och detsamma gäller om du tittar på alla tre variablerna (tid, energianvändning och minnesanvändning). Men om du bara försöker spara energi samtidigt som du använder mindre minne är dina bästa val C eller Pascal.
I slutet av dokumentet tillägger forskarna att de för ytterligare studier skulle vilja undersöka om den totala minnesanvändningen över tiden korrelerar bättre med den förbrukade energin.
De delar med sig av sina data online och menar att det gör det lättare för framtida forskare att jämföra till exempel .NET-språk eller JVM-språk. För utvecklare som arbetar med mobilapplikationer, Internet-of-Things-system eller andra appar som drar nytta av begränsade strömförsörjningar är energiförbrukningen ett stort bekymmer.
Men i slutändan kan studien också lämna programmerare med det som de hatar mest: tvetydighet. Forskarna rapporterar att om du letar efter ett enskilt bästa programmeringsspråk, ”har den här frågan inget konkret och slutgiltigt svar.”
”Även om det mest energieffektiva språket i varje riktmärke nästan alltid är det snabbaste, är det ett faktum att det inte finns något språk som genomgående är bättre än de andra”, avslutar forskarna. ”Den situation där ett språk ska användas är en central aspekt för att avgöra om språket är det mest energieffektiva alternativet.”