XKCD, Randall Munroe // CC BY-NC 2.5

Kotlin vs Java: Kompiliavimo greitis

Jei konvertuosite programą iš „Java“ į „Kotlin“, ar kompiliuoti reikės ilgiau?

Tai straipsnių apie Kotliną 3 dalis. 1 dalyje buvo aptariama „Android“ programos konvertavimas iš „Java“ į „Kotlin“, o 2 dalyje buvo pateiktos mano mintys apie kotlinų kalbą.

Ankstesniame straipsnyje aptariau „Android“ programos konvertavimą iš „Java“ į 100% Kotlin. „Kotlin“ bazinė bazė buvo mažesnė ir labiau prižiūrima nei „Java“ pirmtakas, todėl padariau išvadą, kad perėjimas buvo to vertas. Tačiau kai kurie žmonės nenori išbandyti „Kotlin“, nes nerimauja, kad jis gali nesusidaryti taip greitai, kaip „Java“. Tai tikrai pagrįstas rūpestis; niekas nenori skirti laiko savo kodinės bazės konvertavimui, jei tai sudarys ilgą kūrimo laiką. Taigi, pažvelkime į „App Lock“ programos sudarymo laiko skirtumus prieš konvertuodami ją į „Kotlin“ ir po jos. Nebandysiu palyginti vienos Kotlin eilutės greičio su vienos Java eilutės greičiu. vietoj to, pabandysiu atsakyti į klausimą, ar kodų bazės konvertavimas iš „Java“ į „Kotlin“ paveiks bendrą jos kūrimo laiką.

Kaip aš išbandžiau statybų laiką

Aš rašiau apvalkalo scenarijus, kad paleisčiau „Gradle“ konstravimą pakartotinai pagal įvairius scenarijus. Visi testai atliekami 10 kartų iš eilės. Projektas išvalomas prieš kiekvieną scenarijų, o scenarijams, kuriuose naudojamas „Gradle“ demonas, demonas sustabdomas vieną kartą prieš to scenarijaus palyginimą.

Visi šio straipsnio etalonai buvo atlikti naudojant „Intel Core i7–6700“, veikiantį 3,4 GHz dažniu, su 32GiB DDR4 atmintimi ir „Samsung 850 Pro SSD“. Šaltinio kodas buvo sukurtas naudojant „Gradle 2.14.1“.

Testai

Norėjau paleisti kriterijus keliuose įprastuose naudojimo scenarijuose: švarios versijos su „Gradle“ demonu ir be jo, didėjančios versijos nekeičiant failo, o didėjančios versijos - su pakeistu failu.

Prieš perkeliant „App Lock“ „Java“ kodo bazę buvo 5491 metodai ir 12 371 kodo eilutės. Po perrašymo šie skaičiai sumažėjo iki 4 987 metodų ir 8 564 Kotlino kodo eilučių. Perrašymo metu jokių didelių architektūrinių pokyčių neįvyko, todėl kompiliavimo laiko patikrinimas prieš ir po perrašymo turėtų suteikti gerą idėją apie „Java“ ir „Kotlin“ pastatymo laiko skirtumus.

Švarus stato be „Gradle“ demono

Tai yra blogiausias scenarijus, kai statymo laikas abiem kalbomis: švarios konstrukcijos paleidimas nuo šalto starto. Atlikdamas šį testą išjungiau „Gradle“ demoną.

Štai, kiek laiko užtruko kiekviena iš dešimties versijų:

Dešimt iš eilės tvarkingų statinių be „Gradle“ demono

Šis scenarijus lemia, kad „Java“ kūrimo laikas vidutiniškai yra 15,5 sekundės, o Kotlino vidurkis - 18,5 sekundės: tai padidėja 17%. Kotlin nėra pasiruošęs pradėti puikią pradžią, tačiau tai nėra taip, kaip dauguma žmonių sudarys savo kodą.

Jei norite naudoti švarius statinius, kuriuose nėra „Gradle“ demono, „Java“ sudedama 17% greičiau nei „Kotlin“.

Daug įprasčiau, kad pakartotinai sudarytumėte tą pačią kodų bazę, kai darote pakeitimus. Tai yra toks scenarijus, kuriam buvo sukurtas „Gradle“ demonas, todėl pažiūrėkime, kaip numeriai atrodo jį naudojant.

Švarus stato, kai veikia Gradle demonas

JIT kompiliatorių, tokių kaip JVM, problema yra ta, kad jiems atlikti reikia laiko, kad surinktų jiems vykdomą kodą, todėl proceso našumas bėgant laikui didėja. Jei sustabdysite JVM procesą, prarandate našumą. Kurdami „Java“ kodą, paprastai paleisite ir sustabdykite JVM kiekvieną kartą kurdami. Tai verčia JVM perdaryti darbus kiekvieną kartą, kai tik statote. Norėdami su tuo kovoti, „Gradle“ ateina su demonu, kuris išliks gyvas tarp pastatymų, kad išlaikytų JIT kompiliacijos naudą. Galite suaktyvinti demoną perduodant --daemon „Gradle“ komandų eilutėje arba pridėdami org.gradle.daemon = true į savo failą gradle.properties.

Štai kaip atrodo ta pati švarių konstrukcijų serija, kaip aprašyta aukščiau, tačiau veikiant „Gradle“ demonui:

Dešimt iš eilės statomų „Gradle“ demonų serijų

Kaip matote, pirmasis bėgimas užtrunka maždaug tiek pat laiko, kiek be demono, tačiau vėlesni bėgimai padidina našumą iki ketvirtojo bėgimo. Šiame scenarijuje naudingiau žiūrėti į vidutinį pastatymo laiką po trečiojo važiavimo, kai demonas yra pašildytas. Jei „Java“ važiuoja šiltu keliu, vidutiniškai švarios „Java“ versijos atlikimo laikas yra 14,1 sekundės, o „Kotlin“ - 16,5 sekundės: 13%.

Švariems statiniams sušilus „Gradle“ demonui „Java“ kaupiasi 13% greičiau nei Kotlinas.

Kotlin siekia „Java“, tačiau vis dar šiek tiek atsilieka. Tačiau, nesvarbu, kokią kalbą vartojate, „Gradle“ demonas sumažins pastatymo laiką daugiau nei 40%. Jei jau nenaudojate, turėtumėte.

Taigi, „Kotlin“ kompiliacija yra šiek tiek lėtesnė nei „Java“. Bet paprastai kaupiate atlikę tik kelių failų pakeitimus, o didėjančios versijos turės skirtingas veikimo charakteristikas. Taigi išsiaiškinkime, ar Kotlinas gali pasivyti ten, kur jam svarbu.

Inkrementiniai statiniai

Viena iš svarbiausių kompiliatoriaus našumo savybių yra laipsniško kompiliacijos naudojimas. Įprastas sudėjimas perkompiliuos visus šaltinio failus projekte, tačiau palaipsniui kaups duomenis, kurie failai pasikeitė po paskutinio sudėjimo, ir perkompiliuos tik tuos failus ir nuo jų priklausančius failus. Tai gali turėti didžiulę įtaką sudarymo laikams, ypač dideliems projektams.

Prie Kotlin 1.0.2 versijoje buvo pridėtos pavienės versijos, kurias galite įjungti į savo gradle.properties pridėdami kotlin.incremental = true arba naudodami komandinės eilutės parinktį.

Taigi kaip „Kotlin“ kompiliavimo laikus galima palyginti su „Java“, kai naudojamas inkrementinis kompiliavimas? Toliau pateikiami palyginamieji etaloniniai rinkiniai, kai failai nekeičiami:

Dešimt iš eilės didėjančių duomenų kaupimo nepakeitus failų

Tada išbandysime laipsnišką kompiliaciją su modifikuotu šaltinio failu. Norėdami tai išbandyti, prieš kiekvieną versiją pakeičiau „Java“ failą ir jo Kotlin atitikmenį. Šiame etalone šaltinio failas yra UI failas, nuo kurio nepriklauso jokie kiti failai:

Dešimt iš eilės augančių elementų kaupiama pakeitus vieną atskirą failą

Galiausiai pažvelkime į laipsnišką kompiliaciją su modifikuotu šaltinio failu, kai failas importuojamas į daugelį kitų projekto failų:

Dešimt iš eilės didėjančių statinių pakeitus vieną pagrindinį failą

Galite pastebėti, kad „Gradle“ demonas vis dar naudojasi dviem ar trim važiavimais, kad sušiltų, tačiau po to abiejų kalbų pasirodymas yra labai panašus. Jokių pakeitimų „Java“ užtrunka 4,6 sekundės už kiekvieną šiltą pastatymą, o „Kotlin“ - vidutiniškai 4,5 sekundės. Kai keičiame failą, kuris nenaudojamas jokiuose kituose failuose, „Java“ vidutiniškai reikia 7,0 sekundžių, kad būtų padaryta šilta versija, o „Kotlin“ laikrodis rodomas 6.1 punkte. Galiausiai, kai keičiame failą, kurį importuoja daugelis kitų projekto failų, „Java“ reikia 7,1 sekundės, kad būtų padidintas laipsniškas „Gradle“ demono pašildymas, o Kotlino vidurkis - 6,0 sekundės.

Dažniausiai pasitaikanti konfigūracija - dalinis kompiliavimas, įgalinus inkrementinį kompiliavimą - Kotlin kompiliuoja taip greitai arba šiek tiek greičiau nei Java.

Išvada

Palyginome keletą skirtingų scenarijų, norėdami išsiaiškinti, ar Kotlin galėtų neatsilikti nuo „Java“, kai kalbama apie kompiliavimo laiką. Nors „Java“ švarių statybų metu įveikia „Kotlin“ 10–15 proc., Tai yra gana retai. Daugumai kūrėjų dažniausiai pasitaikantis scenarijus yra dalinis kūrimas, kai didinamasis kompiliavimas daro didelius patobulinimus. Kai veikia „Gradle“ demonas ir įjungtas laipsniškas kompiliavimas, „Kotlin“ kompiuteryje kaupiasi taip pat greitai arba šiek tiek greičiau nei „Java“.

Tai yra įspūdingas rezultatas ir to aš nesitikėjau. Turiu pagirti „Kotlin“ komandą už tai, kad sukūrė kalbą, kuri ne tik turi daug puikių savybių, bet ir gali taip greitai sudaryti.

Jei dėl kompiliavimo laiko jūs bandėte išbandyti „Kotlin“, jums nebereikia jaudintis: „Kotlin“ kaupiasi taip greitai, kaip „Java“.

Neapdorotus duomenis, kuriuos surinkau dėl visų etalonų, galite rasti čia.

Norite visą laiką programuoti Kotlin? Kreipkitės kaip „Kotlin“ inžinierius į „Keepsafe“.