Может ли Java быть быстрее C++?

Есть у меня друг, Стас, с которым мы частенько, как настоящие программисты, особенно при наличии разных средств внутреннего подогрева, регулярно имеем традиционные пузомерки C++ (я) vs Java (он). Понятно, что социальная составляющая является основной в данных беседах, и, очевидно, полного конценсуса тут нет и быть не может, что и хорошо.

Но иногда, уже на трезвую голову, когда я думаю о подобном сравнении, при всем моем желании понять, почему Java в принципе может быть не то что быстрее, а хотя бы не медленнее C++, у меня не хватает аргументов даже для себя самого.

Для начала несколько “дано”:

  • Мы сравниваем С++ 2011, компилируемый в машинный код, и обычную Java 7 (не real-time, embedded или что-то в этом роде), компилируемую в JVM-код, который только в процессе выполнения будет налету через JIT тоже компилироваться в машинный код.
  • Допустим, компиляторы C++ и Java генерируют максимально эффективный код, насколько семантика языка позволяет оптимизировать.

Положим, 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++. Но зачем говорить про скорость то?


Disclaimer

Комментарии