company_banner

Kotlin vs. Java: скорость компиляции

https://medium.com/keepsafe-engineering/kotlin-vs-java-compilation-speed-e6c174b39b5d
  • Перевод


Как уже знают все Android-разработчики, Google недавно объявила об официальной поддержке Kotlin в Android. Многие риски, связанные с использованием этого замечательного языка в Android-проектах, сняты. Но актуальным, особенно для очень крупных проектов, каким является Badoo, остаётся вопрос о скорости сборки. Я был рад обнаружить, что в сети уже есть исследования на эту тему, и переводом одного из них хочу поделиться.


Итак, если вы переводите приложение с Java на Kotlin, будет ли оно компилироваться дольше?


В более ранней статье обсуждалось конвертирование Android-приложения из Java целиком в Kotlin. Кода на Kotlin получалось меньше, и он был удобнее в сопровождении, чем на Java, так что я пришёл к выводу, что оно того стоило. Но некоторые разработчики не хотят пробовать Kotlin, опасаясь, что он может компилироваться медленнее Java. И это беспокойство – справедливо: никто не хочет тратить время на конвертирование кода, если в результате сборка будет длиться дольше. Так что давайте изучим длительность компиляции приложения App Lock до и после конвертирования в Kotlin. Я не буду сравнивать скорость Kotlin и Java построчно, а вместо этого попытаюсь ответить на вопрос, повлияет ли конвертирование всей кодовой базы из одного языка в другой на общую продолжительность сборки.


Как я тестировал длительность сборки


Я написал shell-скрипты для повторяемых запусков Gradle-сборок по разным сценариям. Все тесты выполнялись последовательно по десять раз. Перед каждым новым сценарием проект очищался. Для сценариев, использующих демона Gradle, последний останавливался перед запуском бенчмарка.


Все бенчмарки выполнялись на машине с Intel Core i7–6700, работающим с частотой 3,4 ГГц, оснащённой 32 Гб памяти DDR4, а также SSD-приводом Samsung 850 Pro. Исходный код собирался с помощью Gradle 2.14.1.


Тесты


Я хотел прогнать бенчмарки для нескольких распространённых сценариев использования: чистые сборки с/ без демона Gradle, инкрементальные сборки без изменения файлов, инкрементальные сборки с изменённым файлом.


Кодовая база App Lock на Java содержала 5491 метод и 12 371 строку кода. После конвертирования в Kotlin количество методов уменьшилось до 4987, а количество строк – до 8564. В процессе преобразования в архитектуру не вносились никакие серьёзные изменения, так что измерение длительности компиляции до и после конвертирования должно дать чёткое представление о разнице в продолжительности сборки между Java и Kotlin.


Чистые сборки без демона Gradle


Это наихудший сценарий с точки зрения продолжительности сборки для обоих языков: запуск чистой сборки с холодным стартом. Для этого теста я отключил демон Gradle.


Вот сколько времени заняли все десять сборок:



Десять последовательных чистых сборок без демона Gradle


Средняя продолжительность сборки Java составляет [цифры исправлены по исходным данным автора — прим. переводчика] 24,5 секунд, Kotlin – 32,4 секунд: увеличение на 32%. Не лучшее начало для Kotlin, но большинство людей компилируют свой код по другим сценариям.


Чаще всего мы несколько раз компилируем одну и ту же кодовую базу по мере внесения в неё изменений. Именно для этого сценария был разработан демон Gradle, так что давайте включим его и посмотрим, что получится.


Чистые сборки с включённым демоном Gradle


Одной из проблем JIT-компиляторов вроде JVM является то, что они тратят время на компиляцию исполняемого в них кода, так что по мере его исполнения производительность процесса увеличивается. Но если остановить JVM-процесс, то прирост производительности теряется. При каждой сборке Java-кода обычно приходится запускать и останавливать JVM. В результате он каждый раз заново делает одну и ту же работу. Для решения этой проблемы Gradle поставляется с демоном, который продолжает функционировать между сборками и помогает поддерживать прирост производительности, обеспечиваемый JIT-компиляцией. Включить демон можно с помощью Gradle-команды --daemon, вводимой в командной строке, или с помощью добавления org.gradle.daemon=true в файл gradle.properties.


Вот результат прогона той же серии сборок, но с включённым демоном Gradle:



Десять последовательных сборок с включённым демоном Gradle


Как видите, первый прогон занимает примерно столько же времени, сколько в сценарии без демона. В последующих сборках производительность растёт вплоть до четвёртого прогона. При таком сценарии более целесообразно оценивать среднюю продолжительность сборки после третьего прогона, когда демон уже прогрелся. В этом случае чистая сборка на Java занимает в среднем 14,1 секунды, а на Kotlin – 16,5 секунд: увеличение на 13%.


Kotlin догоняет Java, но всё ещё отстаёт. Тем не менее вне зависимости от используемого языка демон Gradle уменьшает длительность сборок более чем на 40%. Если вы его ещё не используете, то самое время начать.


Итак, полные сборки на Kotlin выполняются чуть медленнее, чем на Java. Но обычно мы компилируем после внесения изменений всего лишь в несколько строк кода, так что инкрементальные сборки должны демонстрировать другую производительность. Давайте узнаем, сможет ли Kotlin догнать Java там, где это важно.


Инкрементальные сборки


Использование инкрементальной компиляции является одним из важнейших свойств компилятора по повышению производительности. При обычной сборке перекомпилируются все исходные файлы проекта, а при инкрементальной – отслеживается, какие файлы изменились с момента предыдущей сборки, и в результате перекомпилируются только эти файлы и те, что от них зависят. Это может оказывать очень сильное влияние на длительность компиляции, особенно в больших проектах.
Инкрементальные сборки появились в Kotlin 1.0.2, их можно включить, добавив kotlin.incremental=true в файл gradle.properties, или через командную строку.


Итак, как изменится длительность компиляции Kotlin по сравнению с Java при использовании инкрементальной компиляции?


Вот результаты бенчмарка при условии отсутствия изменений в файлах:



Десять последовательных инкрементальных сборок без изменения файлов


Теперь протестируем инкрементальную компиляцию при условии изменения одного исходного файла. Для этого я перед каждой сборкой изменял Java-файл и его Kotlin-эквивалент. В данном бенчмарке это файл, относящийся к пользовательскому интерфейсу, от него не зависят другие файлы:



Десять последовательных инкрементальных сборок с одним отдельным изменённым файлом


Наконец, давайте посмотрим на результаты инкрементальной компиляции с одним изменённым исходным файлом, который импортируется во многие другие файлы проекта:



Десять последовательных инкрементальных сборок при условии изменения одного ключевого файла


Как видите, демону Gradle всё ещё приходится прогревать в течение двух–трёх прогонов, но после этого оба языка становятся очень близки по производительности. При отсутствии изменений в файлах у Java уходит 4,6 секунды на прогретую сборку, а у Kotlin – 4,5 секунды. Если мы меняем файл, но он не используется другими файлами, то Java требуется 7 секунд на выполнение прогретой сборки, а Kotlin – 6,1 секунды. Наконец, если изменённый файл импортируется во многие другие файлы проекта, то при прогретом демоне Gradle инкрементальная сборка Java занимает 7,1 секунды, а у Kotlin уходит в среднем 6 секунд.


Заключение


Мы измерили производительность при нескольких разных сценариях, чтобы узнать, сможет ли Kotlin конкурировать с Java по длительности компиляции. При чистых сборках, которые выполняются сравнительно редко, Java превосходит Kotlin на 10–15%. Но чаще всего разработчики выполняют частичные сборки, при которых большой выигрыш во времени достигается за счёт инкрементального компилирования. Благодаря работающему демону Gradle и включённой инкрементальной компиляции Kotlin не уступает, или даже немного превосходит Java. Впечатляющий результат, которого я не ожидал. Выражаю команде разработчиков Kotlin своё почтение за создание языка, который не только обладает прекрасными возможностями, но и компилируется так быстро.


Если вы пока не попробовали Kotlin из опасений увеличения длительности компиляции, то можете больше не беспокоиться: он компилируется так же быстро, как Java.


Сырые данные, собранные мной при прогоне бенчмарков, лежат здесь.

Метки:
Badoo 363,23
Big Dating
Поделиться публикацией
Похожие публикации

Вакансии компании Badoo

Комментарии 33
  • +2
    Не знаю переводил кто данную статью (даже не искал пока), просто все равно не понятно для чего переходить на Kotlin, тем более samsung выпустил Tizen OS, google готовит fuchsia c dart плюс progressive web app, microsoft подсаживает на typescript, это я к чему, хотя и был плохой опыт с phonegap, и не понятно кто выживет из всего этого зоопарка, мобильная разработка движется к кроссплатформенности через ecmascript, ну или Dart. У Вас кстати есть хороший пример по работе с сенсорами используя rxjava было бы интересно посмотреть как это бы выглядело на Kotlin.
    • –1
      Kotlin умеет в JavaScript.
      • 0
        Посмотрел точно, спасибо за подсказку, еще приведу цитату с официального блога
        One of Kotlin’s goals is to be a language that is available on multiple platforms and this will always be the case. We’ll keep supporting and actively developing Kotlin/JVM (server-side, desktop and other types of applications), and Kotlin/JS. We are working on Kotlin/Native for other platforms such as macOS, iOS and IoT/embedded systems.

        если коротко есть Kotlin/JVM и Kotlin/JS, а в планах и macOS, iOS и IoT/embedded systems.

        Тогда смысл есть на перспективу, если начинать новый проект, лишь бы его не шатало как python, swift и т.д.
        • +1
          Kotlin умеет в JavaScript

          Как бы и Java умеет в JS тоже и весьма неплохо. В бытность одного из моих сайтов мне надо былло дешифровывать ссылки, которые были на другом ресурсе закодированы в aes256 (в JS был код от А до Я). Декодирование на оригинале было на aes256 с пост обработкой (перестановки символов и т.д.). Чтобы не ломать бошку, я просто зарядил код в ScriptEngineManager, чтобы не тратить время на реализацию на самой java.

          • 0
            Ну как бы на java можно и php скрипты запустить, а вот проект с Java на JavaScript
            • 0
              Речь о транспилере с языка на язык.
              • 0
                Так есть еще GWT от гугл, который транспайлится в js, на замену которому пришел dart… Под dart есть angular 2, fuchsia… А что есть под Котлин?
              • –2
                Dart как бы это уже давно умеет из коробки, и даже намного лучше…
            • –2
              А да еще буквально полгода назад только начинал осваивать AR (ARToolkit, OpenCV, Google mobile vision), а уже https://awe.media/ или вот еще.
              • +4
                Не хватает сравнения скорости при компиляции с оспользованием кодогенерации apt/kapt, так же при таргетах java6/8(dasugar, retrolambda) а так же multidex. По сути статья в таком виде не имеет ничего общего с реальными крупными проектами, где скорость компиляции действительно важна.
                • +4
                  Средняя продолжительность сборки Java составляет 15,5 секунд, Kotlin – 18,5 секунд

                  При этом на графике для Java почти все результаты попадают в 20-25 сек (и выше), а Kotlin — более 30 сек.
                  • 0
                    Действительно. К счастью автор выложил исходные данные, поправил цифры в переводе.
                  • +3
                    Какая версия kotlinc использовалась при компиляции? Почему для тестов был выбран Gradle 2.14 а не 3.5?
                    • 0
                      Ну да, упомянули 1.0.2, которая уже даже не вчерашний день, а позавчерашний.

                      К тому же сомнительно, что код, полученный автоматической конвертацией, является оптимальным. И ещё мне кажется, что Gradle под Kotlin ещё пока не так хорошо заточен, как Maven.
                      • +1
                        И ещё мне кажется, что Gradle под Kotlin ещё пока не так хорошо заточен, как Maven.

                        Там обратная ситуация. В Gradle и скрипты можно теперь писать на Kotlin и в нем раньше появилась инкрементальная компиляция для него.
                        Да и сама система сборки создавалась не жестко под один определенный язык (по сравнению с Maven), и как результат, имеет более гибкую систему настройки.
                        • 0

                          В каком месте у мавен жестко определеный язык?

                          • 0
                            … сама система сборки создавалась не жестко под один определенный язык
                            • +1

                              Вот я и спрашиваю, где вы это вычитали? Мало того, что уже много лет существуют скажем плагины для сборки .Net проектов (потому что эта сборка в общем-то ничем не отличается от сборки java проектов), или скажем Flexmojo, мало того, что сами плагины пишутся на Groovy, кложе, и еще на некоторых разных языках.


                              В мавене нет никакой привязки к языку, кроме той, что он сам на java написан. Мавен — это лишь формат POM (который в целом language agnostic, да еще и сам давно уже может быть переписан например в виде yaml). Ну и соглашения некоторые, типа жизненного цикла сборки или структуры папок — которые тоже ни к какому языку не привязаны отродясь.

                              • +1
                                Использование Apache Maven – обратная сторона медали
                                Ну и соглашения некоторые, типа жизненного цикла сборки или структуры папок…

                                Поэтому и существуют некоторые сложности для сборки других языков.

                                П.с. пока искал нашел еще одну интересную статью: Maven is broken by design
                                • 0

                                  Сложности? Не большие, чем у любого другого средства сборки. Попробуйте для примера, использовать какой-нибудь современный менеджер зависимостей, типа bower, на машине в интранете, с доступом вовне через прокси, которая генерирует на лету SSL сертификаты. Проникнитесь с ходу.


                                  А соглашения кстати соблюдать не обязательно. Я писал плагины, работающие вообще без наличия POM, это вполне возможно. Пишете на груви, внутри делаете вообще что хотите.


                                  Статья кстати дурацкая. Не, не вся, разумные мысли там есть — только вот решений проблем автор все равно не предложил. А местами просто ржака:


                                  The POM as used in repositories is too verbose for its intended use, and could be vastly improved. Slimming it down would be possible, but enhancing it by making it no longer immutable would break everyone. Unfixable.


                                  Ха (три раза). POM в репозитории — это единственная вменяемая форма модели, с которой вообще можно работать. Я бы сказал, что все другие модели значительно хуже, но опыт применения скажем npm маловать для столь категоричного высказывания.

                                  • 0

                                    Чтоб было понятнее — автор этой статьи считает, что возможность построить модель проекта динамически, используя для этого groovy — это хорошо. На мой же взгляд — это ужасно.


                                    Чтобы так делать, нужно чтобы у вас был gradle в наличии. Причем желательно — той же версии, с теми же плагинами. И надо сборку фактически выполнить, чтобы модель получить. Мало того, что это делает импорт скажем gradle проектов в IDEA просто на порядки медленнее — это еще и не позволяет работать с проектами из других языков. При этом с pom я успешно работал любым инструментом — потому что это xml.


                                    Ну и кто тут привязан к одному языку?


                                    Понятно, что у него другие use cases, но совершенно очевидно, что он обобщает без оснований.

                        • +1
                          Это перевод статьи 2016
                          • 0
                            Насколько я понял, на момент публикации оригинала (9 сентября 2016 года), Gradle 3.5 не был релизнут. Ближайшая стабильная версия — 3.0 (15 августа 2016 года), но есть шанс, что оригинальная статья писалась на пару месяцев раньше, чем была опубликована, что объясняет выбор 2.14 версии (ближайшая стабильная версия на предполагаемый момент подготовки статьи).
                          • –2
                            Ключевой проблемой для kotlin является java, а точнее, юридический отдел oracle. Процесс появления джавы на сервере или на слейве для сборки окутан юридическим маразмом для роботов на 200% процентов. Специальный хук в pbuilder для того, чтобы принимать лицензию до установки пакета.

                            Оно отвратительно. Говорю как админ.
                            • 0

                              А зачем ставить oracle-java? Почему не openjdk? Почему не zulu?

                              • 0
                                Программисты говорят, что неоракловская джава им по религии и внутреннему мироустройству не подходит. Почему в реальности — не знаю. Я админ, а не явописатель.
                                • –2
                                  оракл переводит отдел в котором разрабатывали jvm, в том числе, из Питера в Бангалор. Так что может и стоит взглянуть на альтернативы.
                                  • +1

                                    Какая связь рассмотрения альтернатив с переводом отдела?

                                    • –3
                                      Его теперь будут писать индусы.
                                      • 0

                                        А почему решили отдать разработку индусам вместо петербуржцев?

                                        • 0
                                          на РБК статья была
                              • 0
                                Что насчёт Zulu от Azul?
                                Оно вроде как «чистое OpenJDK»
                                • 0
                                  openjdk не решает ваших проблем? обязательно нужен hotspot? просто интересно

                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                Самое читаемое