Есть у меня друг, Стас, с которым мы частенько, как настоящие программисты, особенно при наличии разных средств внутреннего подогрева, регулярно имеем традиционные пузомерки C++ (я) vs Java (он). Понятно, что социальная составляющая является основной в данных беседах, и, очевидно, полного конценсуса тут нет и быть не может, что и хорошо.
Но иногда, уже на трезвую голову, когда я думаю о подобном сравнении, при всем моем желании понять, почему Java в принципе может быть не то что быстрее, а хотя бы не медленнее C++, у меня не хватает аргументов даже для себя самого.
Для начала несколько “дано”:
Положим, A
– это линейная скорость выполнения машинного когда. B
– скорость компиляции байт-кода JVM в машинный код. Тогда общая скорость выполнения кода:
V(C++) = A1 + B1
V(Java) = A2 + B2
Очевидно, что B1 = 0
, так как С++ генерирует машинный код напрямую и не требует дополнительной работы в процессы выполнения. Но B2
стопроцентно НЕ ноль, так как каким бы эффективным не был компилятор JIT, он ВСЕГДА требует какого-то времени для компиляцию. Более того, JIT не компилирует все сразу, а “подкомпилирует” по мере прохождения путей выполнения. Получается, всегда есть ненулевая вероятность, что неожиданно придется выполнить код, ранее не требуемый, и потребуется время на его компиляцию. Даже если предположить, что компилятор JIT применяет изощренные способы предсказания путей выполнения и делает все, чтобы уменьшить B2
, но B2
по определению не 0. Если был бы 0, то не было бы JVM, а был бы чистый машинный код.
Далее, рассмотрим A1
и A2
. Эти параметры определяют, насколько эффективно компилятор создает код (или байт-код). По моему личному, субъективному и предвзятому мнению, у С++ (не С) больше шансов на оптимизацию благодаря шаблонам (компилятор имеет полноценную семантическую информацию для проведения inline’а) и генерация машинного кода под конкретную платформу (компилятор точно знает, какие машинные инструкции были бы максимально эффективны в каждом случае). Увы, я не особо силен в generic’ах Java, и руководствуюсь только слухами, что в Java они “ненастоящие”, добавленные гораздо позже и уступающие шаблонам C++. И так как компилятор обязан выдать стандартный переносимый JVM-код, то нет возможности оптимизировать под конкретную платформу. Есть надежда, что это сделает JIT, но там уже не будет семантической информации для более глубокой оптимизации. А еще JIT должен быть быстр, то есть будет компромисс между качеством оптимизации и скоростью компиляции. В С++ такой проблемы нет, так как компилировать можно как угодно долго.
Итак, это мои доводы для меня самого, измеренные в виртуальных попугаях. Не получается у меня убедить самого себя, что Java может быть быстрее или хотя бы на уровне с С++ по скорости. Буду рад за помощь в понимании этого вопроса.
Мы со Стасом проводили несколько несложных сравнений, в основном на реализации QuickSort, и Java по линейной скорости кода проигрывала где-то на 10%.
До C++ 2011 можно было говорить, у С++ нет модели памяти и стандартной библиотеки для потоков, поэтому у Java есть шанс выиграть на многопоточности, но сейчас у С++ все на месте. А подходы к многопоточности у С++ и Java, как мне кажется, одинаково неудобные (хотя std::async()
– это очень сильная возможность), и им обоим далеко до goroutines в Go, actor’ов в Scala и т.д.
Понятно, что 10% не всегда делают погоду. Иногда важнее развитые инструменты интроспекции, среды разработки, контролируемое выполнение, замена кода налету и много другое, что дает платформа Java, и не дает “молотилка” C++. Но зачем говорить про скорость то?