XKCD, Randall Munroe // CC BY-NC 2.5

Kotlin vs Java: kompileerimise kiirus

Kui teisendate rakenduse Java-vormingust Kotliniks, kas võtab selle kompileerimine kauem aega?

See on Kotlinit käsitleva artiklite sarja 3. osa. 1. osas arutati Androidi rakenduse Java-vormingust Kotliniks konverteerimist ja 2. osas käsitleti minu mõtteid kotlini keele kohta.

Ühes varasemas artiklis arutasin Androidi rakenduse teisendamist Java'st 100% Kotliniks. Kotlini koodbaas oli väiksem ja hooldatavam kui Java eelkäija ja seetõttu jõudsin järeldusele, et üleminek oli seda väärt. Kuid mõned inimesed ei soovi Kotlinit proovida, kuna nad on mures, et see ei pruugi kompileerida nii kiiresti kui Java. See on kindlasti kehtiv mure; keegi ei taha veeta aega oma koodbaasi teisendamiseks, kui selle tulemuseks on pikad ehitamisajad. Vaadakem siis rakenduse Lock rakenduse kompileerimise aegade erinevust enne ja pärast selle teisendamist Kotliniks. Ma ei ürita võrrelda Kotlini ühe rea ja Java ühe rea kiirust; selle asemel püüan vastata küsimusele, kas Java-koodist andmebaasi teisendamine Kotliniks mõjutab selle üldist valmistamisaega.

Kuidas ma ehituse aegu katsetasin

Kirjutasin korpuse skripte Gradle'i ehituse käitamiseks korduvalt erinevates stsenaariumides. Kõiki teste tehakse kümme korda järjest. Projekt puhastatakse enne iga stsenaariumi ja Gradle deemoni kasutavate stsenaariumide korral peatatakse deemon üks kord enne selle stsenaariumi võrdlusuuringut.

Kõik selle artikli eesmärgid viidi läbi Intel Core i7–6700 sagedusel 3,4 GHz, 32 GiB DDR4 mälu ja Samsung 850 Pro SSD-ga. Lähtekood ehitati Gradle 2.14.1 abil.

Testid

Tahtsin käitada võrdlusaluseid mitmetes tavalistes kasutusstsenaariumides: puhas ehitamine koos Gradle'i deemoniga ja ilma, järkjärguline ehitamine ilma failimuudatusteta ja järkjärguline ehitamine muudetud failiga.

Enne üleminekut oli App Locki Java koodialus 5491 meetodit ja 12 371 koodirida. Pärast ümberkirjutamist langesid need numbrid väärtuseni 4 987 meetodit ja Kotlini koodi 8564 rida. Ümberkirjutamise käigus suuri arhitektuurimuudatusi ei toimunud, seega peaks enne ja pärast ümberkirjutamist koostamisaegade testimine andma päris hea ettekujutuse Java ja Kotlini ehituse aegade erinevusest.

Puhas ehitamine ilma Gradle'i deemonita

See on mõlemas keeles ehitamisaegade halvim stsenaarium: puhta ehituse käivitamine külmkäivitusest. Selle testi jaoks keelasin Gradle'i deemoni.

Kümme ehitust võttis järgmiselt:

Kümme järjestikust puhast ehitust ilma Gradle'i deemonita

Selle stsenaariumi tulemuseks on, et Java ehituse aeg on keskmiselt 15,5 sekundit, Kotlini keskmine aga 18,5 sekundit: kasv 17%. Kotlin pole veel hea algusega, kuid enamik inimesi ei koosta seda koodi.

Puhta ehitusega ilma Gradle-deemonita kompileerib Java 17% kiiremini kui Kotlin.

On palju tavalisem, et kordate sama korpusebaasi, kui teete selles muudatusi. See on selline stsenaarium, mille jaoks Gradle'i deemon oli loodud, nii et vaatame, kuidas numbrid selle kasutamisel välja näevad.

Puhas ehitamine töötab koos Gradle'i deemoniga

JIT-i kompilaatorite, nagu JVM-i puhul on probleemiks see, et neil käivitatud koodi kompileerimine võtab aega ja seetõttu kasvab protsessi toimivus aja jooksul selle käitamisel. Kui peatate JVM-i protsessi, kaotab see jõudluse suurenemine. Java-koodi loomisel käivitate ja peatate JVM-i tavaliselt iga kord, kui ehitate. See sunnib JVM-i tegema oma tööd iga kord, kui ehitate. Selle vastu võitlemiseks on Gradle'il kaasas deemon, mis jääb ehituse vahel ellu, et säilitada JIT-i kompilatsiooni jõudlust. Saate deemoni aktiveerida, edastades käsureal --daemon Gradle'ile või lisades faili gradle.properties org.gradle.daemon = true.

Siin näeb välja sama puhaste konstruktsioonide seeria, nagu ülaltoodud, kuid Gradle'i deemon töötab:

Kümme järjestikust puhast ehitust koos Gradle'i deemoniga töötab

Nagu näete, võtab esimene läbimine umbes sama palju aega kui ilma deemonita, kuid järgnevate jooksude tulemuslikkus suureneb kuni neljanda rajani. Selle stsenaariumi korral on kasulikum vaadata keskmist ehituse aega pärast kolmandat sõitu, kus deemon soojendatakse. Soe jooksu korral on Java keskmiselt puhta ehituse tegemiseks kulunud 14,1 sekundit, Kotlinil aga 16,5 sekundit: tõus 13%.

Puhta ehituse jaoks, kui Gradle'i deemon on soojenenud, kompileerib Java 13% kiiremini kui Kotlin.

Kotlin on jõudmas Java poole, kuid on endiselt pisut taga. Kuid hoolimata sellest, millist keelt kasutate, vähendab Gradle'i deemon ehitamisaegu üle 40%. Kui te seda juba ei kasuta, peaksite seda olema.

Nii et Kotlin kompileerib täielike ehituste jaoks pisut aeglasemalt kui Java. Kuid tavaliselt kompileerite pärast vaid mõne faili muudatuste tegemist ja järkjärgulistel ehitustel on erinevad jõudluse omadused. Uurime siis välja, kas Kotlin saab kätte, kus see oluline on.

Lisanduv ehitab

Kompilaatori üks olulisemaid jõudluse omadusi on inkrementaalkompileerimise kasutamine. Tavaline ehitamine kompileerib kõik projekti lähtefailid, kuid järkjärguline ehitamine jälgib, millised failid on pärast viimast ehitamist muutunud, ja ainult need failid ja neist sõltuvad failid. See võib koostamisaegadele tohutult mõjutada, eriti suurte projektide puhul.

Kotlinile lisati versiooni 1.0.2 lisanduvkogumid ja saate need lubada, lisades kotile.incremental = true oma gradle.properties või lisades käsurida.

Niisiis, kuidas võrrelda Kotlini kommenteerimisaegu Java omadega, kui kasutatakse inkrementaalset kompilatsiooni? Kui faile ei muudeta, on järkjärgulise kompileerimisega võrdlusalused:

Kümme järjestikust järkjärgulist ehitust ilma failide muutmata

Järgmisena katsetame järkjärgulist kompileerimist muudetud lähtefailiga. Selle testimiseks muutsin enne iga ehitamist Java-faili ja selle Kotlini ekvivalenti. Selles võrdlusaluses on lähtefail kasutajaliidese fail, millest muud failid ei sõltu:

Kümme järjestikust lisandmoodulit koos üksiku faili muutmisega

Lõpuks vaatame järkjärgulist kompileerimist muudetud lähtefailiga, kus see fail imporditakse paljudesse teistesse projekti failidesse:

Kümme järjestikust lisandmoodulit koos ühe põhifaili muutmisega

Võite näha, et Gradle'i deemon võtab soojendamiseks ikkagi kaks või kolm korda, kuid pärast seda on mõlema keele jõudlus väga sarnane. Ilma muudatusteta võtab Java aega 4,6 sekundit sooja ehituse kohta, Kotlinil aga keskmiselt 4,5 sekundit. Kui muudame faili, mida ükski teine ​​fail ei kasuta, nõuab Java sooja ehituse tegemiseks keskmiselt 7,0 sekundit ja Kotlin võtab kella 6.1. Ja lõpuks, kui muudame paljude teiste projekti failide poolt imporditud faili, nõuab Java Gradle-deemoni soojenemisel 7,1-sekundilist järkjärgulist ülesehitust, Kotlini keskmiselt 6,0 sekundit.

Kõige tavalisemas konfiguratsioonis - osaline ehitamine, kui juurdekasvukomplekt on sisse lülitatud - kompileerib Kotlin sama kiiresti või pisut kiiremini kui Java.

Järeldus

Võrdlesime mõnda erinevat stsenaariumi, et näha, kas Kotlin võiks koostamisaegade osas Javaga sammu pidada. Kui Java edestab Kotlini puhta ehitise korral 10–15%, on see suhteliselt harva esinev. Enamiku arendajate jaoks palju tavalisem stsenaarium on osalised ehitamised, kus järkjärguline kompileerimine teeb suuri parandusi. Kui Gradle'i deemon töötab ja inkrementaalne kompilatsioon sisse lülitatakse, kompileerib Kotlin sama kiiresti või pisut kiiremini kui Java.

See on muljetavaldav tulemus ja sellist, mida ma ei oodanud. Pean Kotlini meeskonda kiitma selle keele kujundamise eest, millel pole mitte ainult palju suurepäraseid funktsioone, vaid mis suudab seda nii kiiresti koostada.

Kui kompileerimise aja pärast jäite Kotlinit proovima, siis ei pea te enam muretsema: Kotlin kompileerib sama kiiresti kui Java.

Kõigi võrdlusnäitajate kohta kogutud töötlemata andmed leiate siit.

Kas olete huvitatud Kotlini täiskohaga programmeerimisest? Kandideeri Kotsaini insenerina Keepsafe'is.