Комментарии 47
Ммм, мне кажется или ввиду наличия Print/Write в циклах это тест скорости стандартного io?
Да, помимо прямого выполнения, в JVM имеет место быть профайлер ). Конечно, он не успевает отработать на 'коротком' тесте.
Вообще, байт-код не должен вводить в заблуждение - такую композицию можно рассматривать как вынесенный наружу внутренний язык компилятора (в некоторых проектах его называют IL0).
Не, этот тест эффективности отладочных и неоптимизированных версий. Автору стоит попробовать хотя бы включить оптимизацию rustc -C opt_level=3 ./main_primes.rs и он будет приятно удивлён.
Конечно. Но кто сказал, что стандартный ввод/вывод должен в десятки раз отличаться в разных языках?
Если что, это камень и в сторону C++ iostream
Вы правы, что наличие Print/Write имеет влияние и его надо убрать, но на сравнительные результаты не влияет. Дополнил статью.
Каждый раз когда вижу такие статьи на хабре понимаю, что надо всё таки дописать мою статью "Почему ваш кросс-языковой бенчмарк вам врёт". У меня там отличный пример есть, где можно на двух "совершенно одинаковых алгоритмах" получить Java сколь угодно быстрее чем Rust :)
Фантастично то, что люди получив измерения вообще не пытаются даже понять почему они такие числа получили. Вот у человека получается что Rust в 10 раз медленнее, чем Java. И ничего в голове не щелкает, человек публикует статью. Насколько странным должен получиться результат, что бы человек начал искать проблему в своем тесте? В 100 раз должен Rust проиграть Java, в 1000? :) А если бы Java на числодробилки бы оказалась медленнее, там наверное пока в миллион раз её не обгонят никто даже и не почешется, что делает что-то не так :)
Любые измерения производительности кода, где используются компиляторы, должны обязательно идти с указанием версий данных компиляторов и опций, с которыми вы собирали код. В случае Java и Python это должны быть версии JVM и Python. Без вышеуказанной информации все полученные цифры могут смело идти в мусорку.
Да они есть в репозитории, но только не смейтесь, там реально отладочные версии тестировали:
https://github.com/SazonovDenis/test-speed/blob/master/make.bat#L13
Попробовал лазарь. С выводом: 7 секунд, без: 1.5. Так что да. В таком варианте смысла в тестах мне кажется мало. Лучше вывод 'по ходу' отключить.
Вы бы ключи -C debuginfo=0 -C opt-level=3
при вызове rustc
добавили...
По умолчанию Rust компилирует без оптимизаций, надо как минимум делать так:
rustc -C opt-level=3 rust/src/main_horse.rs
Вот документация на эту тему https://docs.rust-embedded.org/book/unsorted/speed-vs-size.html
соотвественно результат у меня на ноутбуке (macbook pro):
rust без оптимизаций:
Attempts: 3, duration: Some(36.852092s)
Executed in 36.86 secs fish external
usr time 36.43 secs 0.16 millis 36.43 secs
sys time 0.20 secs 1.94 millis 0.20 secs
rust с оптимизациями (-C opt-level=3):
Attempts: 3, duration: Some(1.103816s)
Executed in 1.30 secs fish external
usr time 990.80 millis 0.11 millis 990.69 millis
sys time 113.74 millis 2.05 millis 111.69 millis
java:
Attempts: 3, duration: 2.868 sec
Executed in 3.06 secs fish external
usr time 5.00 secs 0.13 millis 5.00 secs
sys time 0.41 secs 1.99 millis 0.41 secs
Это настолько неграмотная статья, что похожа на троллинг.
А теперь скомпилируйте раст в релизе, а не дебаге :) в гитхабе ридми указано, что вы компилируете без оптимизаций. Но даже если там опечатка, и вы действительно компилировали в релизе, то у меня локально совершенно другие результаты. Не в пользу джавы
И уберите тест на IO, если хотите увидеть результаты на CPU, а не оптимизаций вывода в stdout
Вот так просто на коленке взяли и слабали компилятор C? Что ж, верю-верю.
Компилятор C и транслятор Pascal -> C (для дальнейшей компиляции) это совсем разные вещи по сложности), тем более, если нужно не универсальное решение, а для своего кода, в котором вполне могут не использоваться все возможности языка.
У нас в компании вполне себе живет транслятор PHP -> JS для реализации гибкой валидации полей на стороне пользователя, ничего сложного в нем нет.
У нас на 4ом курсе университета была курсовая по написанию транслятора с одного языка в другой. Если оба языка относятся к одной парадигме, имеют схожие языковые конструкции и нужно поддержать только ограниченный набор возможностей, то после изучения необходимого теор. минимума и стандартных иструментов типа bison и flex эта задача становится не сложной.
Если не ставить себе цель «транслировать любой код на FP в адекватный код на Си», то задача решается сравнительно не сложно, в чём вы можете убедиться самостоятельно, если попробуете.
Фактически неудачный пример статьи для спецолимпиады :)
Автору надо было в НАЧАЛЕ статьи признаться в своей слабой компетенции в части ЯП (кроме "любимого") и предложить аудитории "развенчать" его потуги, т.е. предложить свои варианты решения.
Очевидно же, что данный код больше всего времени тратит на вывод. Уж логичнее было всё запихать в массив или строку, а потом уже вывести за раз. Автор бы ещё инкрементально вывод в файл запихал. А уж про оптимизацию забыть при проверке на скорость - это фейл.
Господа, вы все ломаете...В предыдущем посте пытаетесь рассказать, как раст подходит для начинающих, а теперь такого же новичка пинаете ?
Код открыт, пишите пуллреквесты
Да никто новичка не пинает, в комментариях довольно продробно и доброжелательно объяснили, что тут не так (и даже определённое количество плюсов поставили и своя польза от статьи тоже есть). Вообще написание статей новичками вполне имеет смысл, потому что у профи взгляд зачастую "замыливается" и многие вещи, очевидные для них, и остающиеся за кадром, совершенно нетривиальны для новичков, но если новичок делает какие-либо выводы, то они должны быть железобетонно непробиваемы, хотя бы в той области, в которой уже разобрался. В данном случае имело смысл расчехлить Си, сделать буквально пару тестов сравнения Раста и Си, затем пойти в "вопросы и ответы" и спросить "почему все твердят, что Раст сравним по производительности с Си, а вот мои тесты этого не показывают?" и всё встало бы на свои места. Затем погонять Раст с разными опциями оптимизации, заглянуть в листинги ассемблера и получилась бы хорошая статья. Кстати, основное преимущество Раста, на мой взгляд даже не столько в эффективности кода, сколько в том, что там можно достаточно легко и безопасно параллелить вычисления. А для новичков Раст, по моему мнению и правда, не очень подходит, именно потому, что "планка вхождения" в подавляющем большинстве туториалов чуть выше, чем в "учебных" языках.
Отличная доброжелательность. -17 кармы и -49 за статью =)
Остальное, сорри, мусор. Идеология заимствования и единоличного владения противоречит параллелизации. Это один из главных гвоздей в гробик раста, ИМХО конечно. Сэд бат тру.
У Python есть специальная версия, которая использует JIT называется PyPy. Если вы хотите открыть роман "Война и Мир" и подсчитать сколько слов используется в романе и сколько раз они повторяются, то лучше всего для этого подойдёт PyPy. Он довольно быстро справляется с подобной задачей. А если если использовать оригинальный Python, то на полчаса придётся отойти от компьютера.
Основное преимущество языков вроде Java и C# в том, что код скомпилированный в debug режиме по скорости мало отличается от кода скомпилированного в release. Причина в том что для JIT библиотеки классов и рантайм библиотеки всегда используются Release. В тех же плюсах рантайм библиотеки для release и debug - разные
Основное преимущество языков вроде Java и C# в том, что код скомпилированный в debug режиме по скорости мало отличается от кода скомпилированного в release.
Неправда, как минимум для C#. В debug он даже не инлайнит (или инлайнит крайне редко), параметры передаёт через стек и вообще кучу всего не пытается оптимизировать, а в release - инлайнит и оптимизирует. В https://sharplab.io/ легко примеры набрать, посмотрите. Если у вас не видно разницы, то у вас не CPU-bound задача. И бывают баги рантайма, специфичные для release или debug. И всё равно C# кучу возможных оптимизаций не делает (по сравнению с C/C++/llvm), особенно это качается оптимизаций, которые могут нарушить call stack (оптимизация хвостовой рекурсии, например, не делается) - иначе при исключениях потом движок не может сказать, где и что случилось.
Для Java ситуация ещё сложнее.
Всё о чем вы говорите мало влияет на скорость пользовательского кода. Просто потому что никто никогда в здравом уме не делает ни на C# ни на Java задачи требующие серьёзных вычислений. Большая часть вычислений веб-приложений происходит внутри библиотек ASP.NET и Kestrel. Для графического интерфейса в DirectX и их обертках (WPF и WinUI). CPU-bound задачи на C# никто не делает (нужно сделать библиотеку на С++ из которой вытащить функции с нормальными именами и использовать её в C# проекте).
Оптимизации для большинства задач оказывают не такое влияние как многопоточность или SIMD-инструкции. Например я однажды делал графический интерфейс для АЦП. Часть кода преобразующая данные благодаря SSE работала в 6-7 раз быстрее чем написанная на C#. При этом всё на C# могло работать в любой конфигурации что Release что Debug. Если у вас программа на C# сильно замедляется в Debug - это значит что вам нужно оптимизировать hot path чтобы такого не случалось.
Просто потому что никто никогда в здравом уме не делает ни на C# ни на Java задачи требующие серьёзных вычислений.
Это настолько противоречит моему опыту, что я не знаю, как спорить. В банках и в других фин. организациях основная часть хайлоада на jvm. Некоторое количество есть на .net, еще меньшее, но всё еще обнаружимое количество есть на всякой node/js. Следовые количества остального: go, cpp, python и дальше по списку. Немало ресурсов, конечно, съедают "готовые" системы (СУБД, MQ, kafka, мемкеши всякие), но значительная часть вычислений (сожранных процессоров) именно на jvm и .net.
Мы пробовали один из микросервисов в варианте Debug на где-то около тысячи RPS запускать когда искали утечку памяти на .NET Core 2.1 и 2.2 (её так и не нашли, а переход на 3.1 её волшебным образом убрал). Для этого мы просто в кубере удвоили количество инстансов на всякий случай. И не было никакой ощутимой просадки по выполнению запросов. Разница наверно была, но меньше времени выполнения сетевых запросов, например, обращения к SQL Server. Т.е. на .NET Core 2.1 версия собранная в Debug режиме не особо-то и медленнее чем в Release.
Потому что все оптимизации в основном проделывает JIT, а не компилятор.
Сравнивать карьерный самосвал, УАЗ и Феррари - это сильный ход!
Намек на Upd3. У меня на некоторых тестах, код сгенеренный Дельфи и Lazarus для x64 был вдвое быстрее, нежели собранный ими же под x32.
Старые компиляторы просто перестали развивать.
Я проверял на актуальных версиях Delphi 10.3 и FPC 3.x
Это конкретно дельфийский компилятор так развивается - по стандартам x64 положено считать плавающую точку на SSE, поэтому её, так и быть, сделали на SSE. А x86? Да ну, чот страшно трогать, поломаем ещё... оставляем FPU. Отсюда и 2 раза.
У FPC, насколько помню, таких заморочек нет, там x86 компилятор может использовать SSE. Хотя наверное, его нужно принудительно включить.
Компиляторы против компиляторов