Почему C быстрее Java (с точки зрения Java-разработчика)

Original author: Шон Пирс
  • Translation
В листе рассылки Git развернулась дискуссия о том, как язык программирования высокого уровня снижает производительность приложения, в связи с обсуждением JGit. Дискуссия особенно интересна, потому что в ней принимали участие программисты, эксперты высочайшего уровня как в C, так и в Java. Один из них — Шон Пирс (Shawn O. Pearce), известный Java-программист из компании Google, активный коммитер в Eclipse, соавтор Git и автор Java-имплементации Git под названием JGit. В своём сообщении он назвал реальные ограничения, с которыми сталкивается высококвалифицированный разработчик, пытаясь написать эффективный Java-код, сравнимый по производительности с максимально оптимизированным кодом C. Хотя письмо датируется апрелем 2009 года, но некоторые аргументы Шона до сих пор не потеряли актуальность.

List: git
Subject: Re: Why Git is so fast (was: Re: Eric Sink's blog — notes on git,
From: «Shawn O. Pearce» <spearce () spearce! org>


Как было сказано ранее, мы сделали много маленьких оптимизаций в коде Git на C, чтобы добиться реально высокой производительности. 5% здесь, 10% там, и внезапно ты уже на 60% быстрее, чем был раньше. Нико [Питре], Линус [Торвальдс] и Джунио [Хамано] — все они потратили определённое время в последние три-четыре года для оптимизации отдельных фрагментов Git, исключительно для того, чтобы он работал максимально быстро.

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

Например, JGit страдает от отсутствия mmap(), а при использовании Java NIO MappedByteBuffer, нам всё ещё нужно делать копию во временный массив byte[], чтобы получить возможность реальной обработки данных. В Git на C нет такого копирования. Конечно, в других языках высокого уровня метод mmap может быть поудобнее, но все они также склоняются к сборке мусора, и большинство языков пытаются связать управление mmap со сборщиком мусора «для безопасности и простоты».

JGit страдает также от отсутствия unsigned типов данных в Java. Есть много мест в JGit, где нам действительно нужен unsigned int32_t или unsigned long (машинное слово максимального размера) или unsigned char, но эти типы данных просто отсутствуют в Java. Преобразование байта в int, просто чтобы представить его как unsigned, требует дополнительной операции & 0xFF для обнуления sign extension.

JGit страдает от отсутствия эффективного способа представить SHA-1. В коде C можно просто написать unsigned char[20] и сразу скопировать строку в память к контейнеру. В Java byte[20] будет стоить дополнительно 16 байт памяти, и доступ к ним будет дольше, потому что сами эти байты находятся в другой области памяти от контейнера. Мы пробуем обойти это за счёт преобразования из byte[20] в пять int’ов, но это стоит дополнительных машинных инструкций.

Git на C принимает за данность, что операция memcpy(a, b, 20) предельно дёшева при копировании содержимого памяти из дерева (inflated tree) в объект структуры. В JGit приходится платить большой штраф за копирование этих 20 байтов в пять int’ов, потому что позже эти пять int'ов обходятся дешевле.

В других языках программирования высокого уровня тоже отсутствует возможность пометить тип как unsigned. Или заставляют платить похожие штрафы за хранение 20-байтного бинарного массива.

Нативные для Java коллекции (collection types) стали для нас настоящей ловушкой в JGit. Мы использовали типы java.util.* в удобных случаях, и вроде бы почти решили проблему со структурой данных, но они, как правило, работали гораздо хуже, чем запись специализированной структуры данных.

К примеру, у нас был ObjectIdSubclassMap для того, что должно было выглядеть как Map<ObjectId,Object>. Только он требовал, чтобы тип Object, который вы используете как «значение», происходил от ObjectId, поскольку данное представление объекта работает одновременно как ключ и как значение. Это вызывает настоящий кошмар при использовании на HashMap<ObjectId,Object>. (Если кто не знает, ObjectId — это JGit'овский unsigned char[20] для SHA-1).

Как раз пару дней назад я написал LongMap, более быстрый вариант HashMap<Long,Object>, для хэширования объектов по индексам в упакованном файле. Здесь то же самое, стоимость упаковки в Java для конвертации long (самого большого целого) в объект, пригодный для стандартного HashMap типа, была довольно высока.

И сейчас JGit по-прежнему работает медленнее, когда речь идёт об обработке коммита или объекта дерева, где нужно следить за связями объекта (object links). Или когда происходит вызов inflate(). Мы тратим гораздо больше времени на эти процедуры, чем делает git на C, хотя мы пытаемся спуститься как можно на более низкий уровень, насколько вообще позволяет byte[], избегая копирования чего бы то ни было и избегая выделения памяти, когда только возможно.

Что характерно, JGit выполняет операцию rev-list --objects –all примерно вдвое дольше, чем это делает Git, на проекте вроде ядра Linux, а index-pack для файла размером около 270 МБ тоже длится примерно вдвое дольше.

Обе части JGit настолько хороши, насколько у меня хватает знаний для их оптимизации, но мы реально находимся во власти JIT, и любые изменения в JIT могут привести к ухудшению (или улучшению) наших показателей. В отличие от Git на C, где Линус Торвальдс может менять целые фрагменты кода на ассемблере и пробовать разные подходы.

Так что да, есть практический смысл в создании Git на языке высокого уровня, но вы просто не сможете получить там такую же производительность или строгий расход памяти, как у Git на C. Вот чего вам стоят абстракции высокоуровневого языка. Однако, JGit работает вполне нормально; достаточно быстро для того, чтобы мы использовали его как как сервер git внутри Google.

P.S. Сообщение Шона Пирса написано в 2009 году и автор не учитывает изменений, сделанных в Java 1.7. Например, Java сейчас использует escape analysis, чтобы избежать резервирования памяти в куче, когда это возможно.
Support the author
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 138

    +7
    А как вообще высокоуровневый интерпретируемый язык типа Java или Python может быть быстрее нативного и более низкого C? Разве что с JIT, но мне кажется, что при прочих равных C все равно выигрывает. Хотя и на C, и на Java можно написать и медленный/кривой, и быстрый/оптимизированный код :-)
      +27
      А как Си может быть быстрее Ассемблера? :) Оптимизирующие трансляторы могут «писать» более эффективный код, чем программисты, по крайней мере средние, а не гении, держащие в голове всё, от особенностей микрокода различных процессоров до высокоуровневых абстракций.
        +16
        Скажу даже больше, сейчас столько всяких SSE различных версий и прочих наворотов, что написать более или менее большой ASM-код с учётом их всех под силу не каждому даже хорошему ASM-программисту (не потому что он не знает как, а потому что просто мозги закипят от количества нюансов) в компиляторе же все эти «джедайские» техники собираются не одним десятком программистов.

        Однако быстродействие нужно далеко не во всех областях программирования, иногда важна скорость разработки, стоимость поддержки, и.т.д. В итоге даже если языки типа Java или Python могут быть более подходящими даже если их скорость будет ниже.
          +6
          >Однако быстродействие нужно далеко не во всех областях программирования, иногда важна скорость разработки, стоимость поддержки, и.т.д.

          Это-то очевидно, я больше о том, что сейчас высокоуровневые трансляторы позволяют сэкономить и скорость разработки, и скорость выполнения. Ну или близко к тому.
          • UFO just landed and posted this here
              +3
              Так он и оптимизируется (про распараллеливание не уверен). Компилятор по моим замерам оптимизировал мои программы по времени выполнения в 10-30 раз (высокопроизводительные мат задачи обработки больших матриц).
              Покажите мне другой компилятор, способный настолько оптимизировать код? (кроме brainfuck и аналогов :)
              • UFO just landed and posted this here
                  +2
                  В 10-30 раз по сравнению с отключенной оптимизацией.
                  На С никогда не получал более 400% скорости от -O2 по сравнению с отключенной оптимизацией. И тоже задачи очень затратные, перемалывание чисел в общем-то.
                    +1
                    Кстати, может сейчас на меня любители интел набросятся, но на моем опыте их компилер оптимизирует хуже, чем оный от студии :)
                    Большой статистики у меня нет, в общем-то только одна программа. Но процентов на 5-10 медленнее было. Не утверждаю, что он хуже в принципе, но вот такой факт есть.
                      0
                      А у вас процессор какой?
                        +2
                        Интел i3, я бы если бы amd был и не стал бы говорить :)
                        0
                        У меня подобное в сравнении icc и gcc.
                        Тестил на i5 750 и на MTL (Manycore Testing Lab).

                        В моем случае, я видимо не умею готовить icc. Но на -O2 разрыв ощутимый.
                          0
                          Я использовал его, как плагин к студии, все настройки вроде довольно понятные, все попробовал в нескольких вариантах — и все равно медленнее код выходит. Хотя тоже не исключаю, что руки кривые, все может быть.
                            +4
                            У icc и gcc флаги имеют разный смысл. Тоже что у gcc значит -O2 у icc «примерно» -fast.
                            Который выставляет -ipo, -O3, -no-prec-div, -static, и -xHost. (последние 2 как раз и делают не точным соответствие).
                            Вообще вопрос сравнения компиляторов намного более сложный чем «выставил одинаковый(по названию) флаг».
                      +4
                      Если вы внимательно читали мои комменты, то я говорил о средних, а не хороших. Когда я писал на Си, то мне было интересно, во что на ассемблере превращаются мои программы, чтобы если что сделать ассемблерную вставку, и делал, в начале 90-х (без особого профита, чисто ради искусства). Где-то к концу 90-х я перестал смотреть, чтоб не расстраиваться, видя как компилятор выносит count() за цикл.
                        +8
                        «Аналогичный случай был в нашей деревне...» (С)

                        С какого-то момента стало не достаточно просто знать за сколько тактов выполняется та или иная инструкция. А заниматься ручной оптимизацией, чтобы потом увидеть, как грамотный компайлер обгоняет её просто из-за того, что он помнит больше процессорных тонкостей уже не в кайф. Не говоря уж о том, что абсолютно бесперспективно.
                          +7
                          Это ладно тонкости, а вот когда он алгоритм лучше тебя понимает :)
                        +5
                        В смысле кто чего не видел?
                        Линусовская sha1 компилируемая gcc обошла по скорости оптимизированную ассемблерную реализацию из openssl.

                        Но если говорить о JIT'ах, то их преимущество в том, что они работают на основе runtime статистики на реальных данных.
                        • UFO just landed and posted this here
                            +22
                            Навеяло, где-то цитату видел:
                            «Вот же молодежь пошла, им уже С — низкоуровневый язык!» ©
                              0
                              Ну как бы Си всегда был низкоуровневым по близости к железу.
                                +2
                                Это смотря как определять низкоуровневость.
                                  +2
                                  Адресная арифметика, прямая и декларированная зависимость базовых типов от архитектуры.
                                  Ключевое слово register :)
                                    +3
                                    Ну ладно, я определяю низкоуровневость так: чем больше абстракции от машины, тем высокоуровневей.
                                    В ассемблере я пишу:
                                    cmp eax, 0
                                    зная, что я выполняю инструкцию cmp, которыя регистр флагов меняет, да еще и егистр использую.
                                    В си же я пишу:
                                    if(a == 0)
                                    Буквально говоря «что делать» а не «как делать». И использую не регистр, а абстрактную переменную. Еще и типизированную.
                                    Таким образом си гораздо высокоуровневей ассемблера и в сравнении с ним называется высокоуровневым.
                                      +5
                                      Аналогичным образом по приведенным вами причинам я называю его низкоуровневым при сравнении с джавой. Но в любом случае на мой взгляд субьективно си гораздо более высокоуровневый, чем низкоуровневый, так как я говорю компилятору «что делать» а «как делать» он выбирает сам.
                                        +1
                                        Ну а где же тут ассемблерные макросы, например?
                                        Или автоматическое распределение памяти под всякую статику, с метками, с выравниванием, со всеми делами?

                                        Ассемблер много чего умеет делать еще.
                                        Это же не просто транслятор мнемоники машинных кодов.
                                        Где-то я помню было автоматическое именование регистров и алиасы для них.

                                          0
                                          Ну так и C расширяли счетчиками ссылок и прочими штуками. Речь идет о чистом языке. А абсолютно все ассемблеры являются трансляторами мнемоники машинных кодов. Что «где-то есть такая-то фича» — это не самый лучший аргумент. В любом компиляторе C есть if, а макрос аналогичный if есть не в любом ассемблере, да и называться они могут по-разному, и даже использоваться.
                                            +1
                                            Абсолютно все ассемблеры, с которыми я имел дело (кроме одного tasm.com размером в несколько килобайт) понимали все вышеперечисленное. Урезанные реализации Си я тоже видел.

                                            Подытожу.
                                            Ассемблеры предоставляют не так уж и мало абстракций, как это кажется. Просто сейчас ими мало кто пользуется, так как проще сделать всё на Си, а только некоторые вставки на асме, чтобы не писать прямо в машкодах.
                                            +4
                                            Да и вообще, че тут спорить, программист микроконтроллеров все равно будет считать си высокоуровневым, а веб программист низкоуровневым, все зависит исключительно от личного мнения.
                                              +1
                                              Я, как веб-программист, назвал бы Си среднеуровневым. Тем более, что я на нём писал под веб. По сравнению с PHP логику писать почти так же (что не удивительно), проблемы были с CGI-интеграцией и шаблонизацией (я и слова-то такого тогда не знал). Но в целом, не могу сказать, что качественный скачок, скорее воспринимал PHP (тогда 3) как «сахар» к Си, избавляющий от проблем с CGI, шаблонами и выделением/освобождением памяти.
                                                0
                                                Ну конечно из таких мнений всегда кто-то выбивается, это же не что-то абсолютное. Я о среднем по больнице все-таки.
                                                +1
                                                Ну фиг знает, у меня знакомые микрушкини воспринимают Си, как такой более удобный макроассемблер :)
                                                  0
                                                  Так ведь и я недалек от такого же мнения.
                                                  0
                                                  от личной специализации, привычного уровня абстракции.
                                                  «личное мнение» — слишком произвольная вещь и в вашей фразе говорит ни о чём.
                                          +1
                                          Создавался он как раз наоборот высокоуровневым, чтобы можно было писать код, не задумываясь о реальном железе.
                                            0
                                            Ага, то-то там испокон века восьмиричные константы, 16-и битный int и 32-й long. Помню, сколько программ обиделось, когда компайлеры стали думать, что int это теперь 32 бита.

                                            Это я к тому, что на архитектуру-то был ориентирован очень даже.

                                            «Уровневость» языка скорее определяет не привязанность к архитектуре, а набор абстракций.

                                            Набор абстракций Си совсем не сильно отличается от какого-нибудь макроассемблера.
                                              +2
                                              Гуляет же по инету рассказ Кернигана, если не ошибаюсь, где он рассказывает, что С появился с целью успростить разработку ПО на нескольких архитектурно разных машинах, которые у них тогда были «под рукой». Ну и еще для портирования игрушки с одной машины на другую :)
                                                +1
                                                Извиняюсь, вспомнил. Рассказ Дениса Ритчи, и C был создан для написания портируемого UNIX 3.
                                                –1
                                                Кстати, именно поэтому я очень люблю расширение от MS: типы __intn, где n- число бит в числе. __int8, __int16 и так далее. Отличная вещь — сразу понятно, что за число.
                                                  +2
                                                    0
                                                    А вас не смущает, что это C99, а в студии предыдущий стандарт?
                                                      +1
                                                      для проблемных компиляторов www.boost.org/doc/libs/1_48_0/boost/cstdint.hpp
                                                        0
                                                        А вас опять же не смущает, что это C++, а не C? И даже если это можно скомпилировать C-компилятором, не смущает ли вас, что не у всех есть буст? И ставить ради этого сию монструозную библиотеку — несколько странно.
                                                          +1
                                                          visual c++ — это компилятор C?
                                                          Очень часто практикуют тащить из буста только те части, которые используются в проекте. Так что не вижу никаких проблем с cstdint из буста.
                                                            –1
                                                            В наборе есть компилятор C. Для его использования надо включить опцию /TC или в настройках проекта «Compile as C code».
                                                              0
                                                              Ну тогда не проблема вырезать namespace'ы из cstdint и использовать стандартные конструкции в проекте, а не MS specific.
                                                                0
                                                                Ну потому я примерно так и делаю :)
                                                          0
                                                          Упс, не заметил сначала, но C компилятором это нельзя собрать ибо namespace.
                                                        • UFO just landed and posted this here
                                                      0
                                                      Макроассемблер — в него можно добавить я думаю любой уровень абстракций (ассоциативные массивы, например), на то он и макро.
                                                      Но ведь мы, как я понял, говорим об языках в их изначальной ипостаси, о C и об ассемблере?
                                                  0
                                                  Даже Java можно считать низкоуровневой, просто для другой целевой платформы, для jvm.

                                                  Так как всякие объектно-ориентированные штучки для ассемблеров тоже были.
                                                    0
                                                    Сейчас уже новое поколение, для которых C++ — низкоуровневый.
                                                      +2
                                                      Подрастает поколение «DSLщиков», для которых ruby низкоуровневый язык :) Кстати, есть доля правды, пользуюсь постоянно capistrano и иногда рельсами — ruby практически не знаю, что не сильно мешает :)
                                                        +1
                                                        Аналогично с Jquery и чистым Javascript. Уже встречал таких разработчиков, кто знаком только с Jquery.
                                                          0
                                                          Ой, как это?
                                                          А что они писать-то умеют тогда?
                                                            +1
                                                            Не то чтобы совсем не знают JavaScript, только элементарные конструкции. Я как-то тоже с удивлением узнал, что в JavaScript есть объекты и наследование :) Хотя считал, что его знаю. Теперь не считаю )
                                                              0
                                                              Стесняюсь спросить, а как насчет замыканий?
                                                              Это удивление уже посещало? :)
                                                                –2
                                                                Узнал о них в JavaScript когда они появились в PHP и пытался понять что это такое и зачем нужно. Честно говоря, так и не понял. Как сейчас с traits. Анонимные функции и функции высшего порядка — понятно, ясно и удобно. Про замыкания прочитаю в очередной раз, вроде теория ясна, workflow примеров тоже ясен, но вот что это даёт на практике — не осеняет.
                                                                  +2
                                                                  На практике дает возможность функции таскать видимый контекст с собой. Только-то и всего, в общем-то :)

                                                                  Смысл не в том, что функция анонимна, а в том, что когда мы её создали вот тут вот и вокруг нее были какие-то переменные. То потом, когда мы передали её, как колбэк невесть куда, и там в этом «невесть где» наша функция будет видеть эти переменные.

                                                                  Наверно каждый второй пример с
                                                                  setTimeout(function() {… }, millis);
                                                                  что-нибудь подобное использует.
                                                                    +1
                                                                    На практике даёт spaghetti code. Это полезная вещь, но только в умелых руках.
                                                                      –2
                                                                      Тогда вникать не буду :) JavaScript не основной мой язык.
                                                                        +1
                                                                        Понимание таких вещей делает программиста сильнее вне зависимости от того на каком языке он программирует.
                                                                          +2
                                                                          Нельзя объять необъятное. Если знания не востребованы, то они забываются. Вот я сейчас без Гугла не вспомню ни Ассемблера, ни Фортрана, которые в институте проходили. Да что там, не вспомню Бэйсика (что-то посложнее 10 INPUT A 20 PRINT A 30 GOTO 10), на котором лет 5 писал в самом юном возрасте и по идее должен лучше всего запомнить (импринтинг типа).

                                                                          Но я знаю что замыкания существуют и относятся к области использования функций высшего порядка. Когда обычных «незамкнутых» функций мне хватать не буду, я обращусь к литературе по замыканиям, чтоб прикинуть не помогут ли они мне. Да даже если бы не знал. В свое время мне не хватало возможности в методе родительского класса вывести имя наследуемого (задача сложнее была, но сводилась к этой). Начал гуглить и увидел, что это называется Late Static Binding и оно есть в бете PHP 5.3.
                                                                            0
                                                                            >> Когда обычных «незамкнутых» функций мне хватать не будет

                                                                            Врядли ты (ничего что я на ты?) вспомнишь о возможностях которые нет привычки использовать — как нибудь извернешься и сделаешь на «обычных, незамкнутых функциях»

                                                                            >> В свое время мне не хватало возможности в методе родительского класса вывести имя наследуемого

                                                                            А что ты скажешь о возможности выбрать полиморфный метод в зависимости от того, КЕМ (в смысле методом какого объекта) он был вызван? Что, необычно выглядит? А ведь насколько можно упростить было бы программирование систем разграничения доступа! Вот тут более подробно про такие вещи.
                                                                              0
                                                                              В данном конкретном случае вряд ли. Всё-таки замыкания на слуху и хоть какое-то представление у меня о них есть. А вот с LSB, даже не смотря на то, что гуглил, пришлось выворачиваться — фича была только в бете. Сейчас, например, с трейтами такое положение. Возможность упростить программу есть, но как скоро её можно применять в продакшене — неизвестно.

                                                                              Угу, необычно и заманчиво, и гуглить в голову не приходило, а сразу писал
                                                                              ...
                                                                              public function doSmth($user) {
                                                                                if ($user instanceof User)
                                                                                  $this->doSmthAsUser();
                                                                                else if ($user instanceof Admin)
                                                                                  $this->doSmthAsAdmin();
                                                                              }
                                                                              ...
                                                                              


                                                                              P.S. SICP, каюсь, неосилил. Читал в свободное время, потом забросил почему-то, а сейчас другие книги читаю.
                                                                      0
                                                                      В JavaScript их понять действительно сложнее, а привязать к реальной жизни — вообще тяжело. Но все меняется после внимательного прочтения SICP, где примеры даны на Scheme
                                                        0
                                                        Если говорить о высоком уровне, то надо и задачи соответствующие рассматривать. Например, сборка мусора в Java вполне может работать эффективнее чего-нибудь сишного на рефкаунтерах.

                                                        Разумеется, можно и на нижний уровень притащить всякие умные гарбеджколлекторы и прочий рантайм, только тогда там уже не Си будет а такая же Java :)

                                                          +1
                                                          будет Си, во многих больших проектах есть различные специализированые гарбеджколлекторы, так же используются различные аллокаторы для объектов с разным сроком жизни.
                                                          А вообще почему C быстрее .Net(Java) отлично рассказали майкрософтовцы на build'е. И самый главный их тезис в том что писать быстрые приложения на Си проще чем писать быстрые приложения на .net(вспоминаем проекты на java/.net в которых используются те же memory pool'ы, различная магия с рантаймом и прочая муть). Ведь когда я пишу на Си мне достаточно знать как работает железка и ос, а в случае с java нужно знать ещё и о том как работает jvm.
                                                          В теории конечно jvm всё делает идеально, работая с нашим простым кодом, но как мы видим спустя столько лет/влитых денег в java/.net, что-то даже близко не приблизились к этим идеалам.
                                                            0
                                                            Спустя столько лет мы видим, что Java является стандартом дефакто для серверного программирования с вкраплениями Си только там, где это удобно и оправдано.

                                                            «достаточно знать как работает железка и ос» — а Вы только под одну железку пишете что-ли?
                                                            Я вот порой даже не знаю, на каком железе оно там у меня в облаке сейчас трудится…
                                                              +2
                                                              >Спустя столько лет мы видим, что Java является стандартом дефакто для серверного программирования
                                                              Так можно сказать что и php производительный тк на нём реализовано большинство веб сайтов в интернете.

                                                              >а Вы только под одну железку пишете что-ли?
                                                              Примерно представляю с какой железкой работаю. Так же как и джависты, которые занимаются оптимизацией кода.
                                                              Если вам не приходится заниматься оптимизацией кода на джаве, то это же не говорит о том что другие этого не делают. Я достаточно часто встречался с различным оптимизациями на .net и java, когда учитывалось на каком железе оно будет крутиться.
                                                              Я ведь говорю о том что писать _производительный_ код проще на Си чем на java, а не о том что писать обычные сервера выгоднее с использованием джавы.
                                                          +1
                                                          >сегодня

                                                          Пройдёт N лет и мы будем обсуждать есть ли смысл писать на Java/Python/..., если есть высокоуровневые языки, которым не нужны понятия цикла, ветвления, переменной, объекта, функции и т. п., которые процентов на 20 медленнее Java, но на 100% быстрее писать (диктовать?) код. А ещё через M будем сравнивать уже эти с обычным разговорным языком.

                                                          Трансляторы как раз та часть ИТ, где более всего очевидно, по-моему, куммулятивное накапливание знаний, опыта и best prictices отдельных людей в пользу всех пользователей. А растущие аппаратные возможности позволяют все эти знания применять в интерактивном режиме.
                                                            +1
                                                            Это время уже давно настало.
                                                              0
                                                              Вон рубисты шага ступить не могут, чтобы не реализовать быстренько какой-нибудь DSL и не писать на нём :)

                                                              Про лисперов я уж и не говорю — программа рисуется по сути сразу из AST деревьев, где чуть ли не в каждом узле свои языковые конструкты.
                                                              (утрирую :)
                                                                0
                                                                Когда писал тоже про руби и его DSL думал, но подумал, что не совсем корректно. Оно может и выглядит как почти человеческий язык, но всё же транслятор воспринимает абстракцию DSL семантически как элемент руби, а DSL только в головах. Но вообще да, этот путь я имел в виду и прежде всего конкретно ruby-way, с Lisp и подобными ему как-то не сложилось.
                                                                  0
                                                                  Как опытный лиспер — подтверждаю — через месяц разработки нового проекта я уже пишу не на лиспе, а на реализованном поверх лиспа своем DSL-языке
                                                                +4
                                                                Попробуйте посжимать видео с помощью x264 с опцией --no-asm, разница в 3-5 раз обеспечена. Там где нужна производительность ассемблер еще никто не отменял. В вышеупомянутом x264 в ассемблерных исходниках 26 тысяч строк против 51 тысячи сишных, то есть треть проекта написана на асме.
                                                                  +2
                                                                  Я в свое время писал bitblt на Турбоассемблере с опцией .286 и очень гордился этим.
                                                                  А скажите, сейчас есть в природе такая железка, которая не делает это аппаратно?
                                                                    0
                                                                    Прислать S3 из загашника?
                                                                    +1
                                                                    Ну, вообще говоря не факт, что такое количество ассемблера там на самом деле оправдано.
                                                                    Хотя эффекты типа описанных в топике на границе java/c, наверняка есть и на границе c/asm.
                                                                      +1
                                                                      Мне кажется что половина а то и больше инструкций в новых SSE Направлена на (де)кодирование видео.

                                                                      Собственно поэтому там асм и лидирует.

                                                                      Вы привели по сути единственный пример где ассемблер и вызов определенных инструкций безмерно рулит.

                                                              +1
                                                              вы сейчас в плену мифов.

                                                              Компилятор не может действительно эффективно, так что бы в 100 раз быстрее, использовать SSE инструкции.

                                                              Всё дело в том, что действительно эффективное использование этих инструкций возможно тогда, когда программист понимает, что он пишет код не под абстрактный x86, а под SSE модуль, который накладывает другие требования на организацию данных в памяти.

                                                              Компилятор не может развернуть ваши структуры данных из row based в column based, что бы получить нужное ускорение.

                                                              Так что увы и ах, но «ассемблерные вставки», а точнее просто вызовы крайне специализированных функций до сих пор остаются возможностью именно человека.
                                                                +2
                                                                Я в плену практики. Я сам в программирую на ASM (в качестве хобби)
                                                                Низкоуровневый код можно написать более быстродействующим. Да, компы пока не стали умнее человека. Только вот в чём дело, у человека мозг не железный, человеческий фактор ВСЕГДА оставляет свой отпечаток. Даже если ты супер-программист, от ошибок ты не застрахован…
                                                              –2
                                                              Смеяться будете, скомпилил прогу с SSE2 и оптимизацией по скорости (релиз конфигурация, компилятор — студия 2010), работает медленее, чем дебаг и без оптимизаций.
                                                              +8
                                                              Высокоуровневый язык может быть эффективнее С за счет более широких знаний о коде — вплоть до смысла стандартных процедур. А интерпритируемый — за счет оптимизации в JIT-компиляторе под хост машину, а не ту машину, на которой компилировалось.
                                                              Другое дело, первое — субьективный факт, т.к. сам программист имеет наиболее высокоуровневую и полную информацию о коде и он может проводить наиболее высокоуровневые его оптимизации. Другой вопрос — будет ли? И стоит ли оно того? А компилятор позволяет делать это бесплатно.
                                                              Зато второе — реальное преимущество, учитывая, что расходы на JIT-компиляцию не столь уж велики. Особенно, если задача очень сильно пожирает процессорное время, то можно считать, что они пренебрежимо малы по сравнению с самой задачей.
                                                                +3
                                                                в топике как-раз и описаны те фишки, которые никакая JIT не скомпенсирует, потому что в языке сейчас не предусмотрено способов описать выполняемую задачу корректнее, пригоднее к оптимизации — нет беззнаковых типов данных, нет средств описать структуру поверх загруженного массива байтов и т.п. ограничения.

                                                                Кстати, может быть появятся, коли уж выявлены. Странно что с 2009 года подвижек в эту сторону не видать.
                                                                0
                                                                Java может иногда быть быстрее С++, если С++ скомпилирован под какой нибудь i-386, т.е. компилятор не знает о том, что он имеет право использовать наборы инструкция SSE 3/4 и прочее, в то время как JIT может использовать при компиляции все инструкции, доступные на том процессоре, на котором работает программа.

                                                                Но в большинстве случаев да, конечно, С++ скомпилированный GCC под конкретный процессор I-7, например, с максимальной оптимизацией, будет быстрее.

                                                                Мои имхо.
                                                                  0
                                                                  habrahabr.ru/blogs/programming/136210/?reply_to=4531495#comment_4531318 дело говорит — под возможность использования SSE и т.п. фишек что вручную, что оптимизатором, нужно ещё и заранее данные в памяти и переменных организовать соответственно. Компиляторы настолько программу переписывать пока не умеют.
                                                                +14
                                                                Без unsugned в java реально хреново. Попробуйте реализовать какой нибудь алгоритм для работы с данными(крипто, сжатие, кодирование) и вы офигеете от этих & 0xFF
                                                                  0
                                                                  Если у вас очень много мест такого использования не задумывались ли вы описать класс UnsignedLong?
                                                                  +6
                                                                  А расскажите пожалуйста, на кой черт этот JGit вообще нужен? Чем не устраивает сишный гит?
                                                                    0
                                                                    Наверное, эксперимент.
                                                                      +8
                                                                      compile once run anywhere?
                                                                        –6
                                                                        да ну?! достаточно громкая фраза. Где можно скачать пример скомпилированного GUI-приложения, чтоб запустить на паре платформ?
                                                                          +2
                                                                          Да почти любое приложение на Swing кроссплатформенно. На StackOverflow также обсуждался вопрос, как собирать приложения на SWT, чтобы зависимости от разных платформ встраивать в JAR, чтобы тоже запускать «где угодно»(на платформах, под которые есть реализация SWT).
                                                                            0
                                                                            Клиент Промсвязьбанка :)
                                                                            Если правильно помню еще IntelliJ IDEA, но при чем здесь GUI приложения?

                                                                            Java, как платформа, реально снимает кучу проблем с совместимостью и кросплатформенностью.
                                                                            Т.е. если окружение уже есть, то совсем не хочется озадачиваться вопросом «как же запустить здесь бинарник?», даже если в теории git работает несколько быстрее JGit.
                                                                              0
                                                                              ох вы как сразу идею, можно же попроще: жаба, она же vuze, она же azureus
                                                                          +4
                                                                          Для использования в разных Java-based системах.
                                                                            0
                                                                            Устраивает всем, но мне как-то раз пришлось использовать git под виндой. На той винде стоял антивирь с проактивной защитой и очень весело было добавлять в исключения mv.exe, cp.exe и тд.

                                                                            Вот под винду я бы пользовался JGit
                                                                              0
                                                                              под виндой нужно TortoiseGIT использовать ;)
                                                                                  0
                                                                                  там написано «тормозит с отрисовкой на больших репозитариях».
                                                                                  Это да, наверно на тех репозитариях, где существенны тормоза Java-реализации по сравнению с C-шной, тормоза отрисовки черепаха ещё заметнее.
                                                                                  0
                                                                                  Черепаха хороша, даже при разработке в Eclipse предпочитаю её, а не плагин EGit (ибо порой глючит при Merge/Push), но некоторые вещи (по сути мелочи, но всё же) вызывают полное недоумение. Банальнейший пример: переключиться с ветки на ветку.
                                                                                  Черепаха: клик — TortoiseGit — Switch to… — появляется диалог, где в комбобоксе нужно выбрать ветку — нажать ОК. Вопрос: почему бы сразу не сделать менюшку со списком веток?
                                                                                  Ибо в EGit это: клик — Team — Switch to… — выбраь ветку прямо в меню. И всё.
                                                                                  Мелочь — а раздражает %)
                                                                              • UFO just landed and posted this here
                                                                                0
                                                                                На www.jgit.org можно найти зачем он был создан — создание плагина для Eclipse.
                                                                                  +1
                                                                                  это я прочитал, мне непонятно, почему нельзя сделать плагин в виде интерфейса к нативному гиту
                                                                                    +3
                                                                                    Я не берусь точно говорить, что именно сыграло роль в данном случае, но аргументы обычно такие:

                                                                                    1) Если я не ошибаюсь — для Git, в отличие от SVN, не предусмотрено готовой библиотеки имеющией 'нормальное' API. Плагин для SVN (Subclipse) к Eclipse как раз использует нативные библиотеки, как основной вариант (но можно переключиться на использование pure java имплементации).
                                                                                    Сценарий интеграции с внешними утилитами через запуск исполняемого файла и считывание его потоков вывода всегда менее удобно и надежно, чем работа через полноценое API. У тому же накладывает ряд органичений. Разработчики всегда избегают данного варианта, если имеется такая возможность.

                                                                                    2) При наличии библиотеки ее лицензия может быть не совместима с лицензией продукта для которой пишется плагин (вроде бы это не наш случай).

                                                                                    3) Как уже отмечали выше — гарантировать, что плагин для Eclipse будет работать на всех платформах, на которых будет работать сам Eclipse.

                                                                                    Таким образом создание JGit дало два значимых плюса:

                                                                                    1) Создание более удобного и главное — надежного способа работы с ним.

                                                                                    2) Избавление пользователя от необходимости ставить Git, так как это может быть не совсем тривиально — как в случае с windows. Ведь в случае ошибки при установке бочку будут катить на плагин и на то, как сложно с ним работать.

                                                                                    Из минусов реимплементации Git — гланым является то, что работает он немного не так как оригинальный. Я наталкивался на небольшие отличия при мерже веток и отслеживании истории переименованых файлов. Но это мелочи, которыми можно пренебречь. Плюсы JGit, в виде удобной и экономящей время библиотеки для java разработчиков, — перевешивают все эти незначительные минусы.
                                                                                      +1
                                                                                      Спасибо за развернутый ответ!
                                                                                –1
                                                                                Название повергает в смех! Там с чье точки зрения не смотри — ответ один!
                                                                                  0
                                                                                  Акцент на слове «почему», а не «быстрее».
                                                                                    0
                                                                                    Видимо QtRoS имеет ввиду ответ «потому, что C нативный».
                                                                                      0
                                                                                      Не уверен, что любой «нативный» компилятор, да ещё с отключенной оптимизацией выдаст код, работающий быстрее JIT.
                                                                                        0
                                                                                        Ну давайте тогда ставить их в те же условия, JIT будет тоже без оптимизаций. В итоге получим оверхед на JIT и ничего больше.
                                                                                          0
                                                                                          Зачем? :) Тезис звучит (вернее я его так понял) «нативный компилятор всегда лучше ненативного». Достаточно одного случая. чтобы его опровергнуть. Ещё вариант — взять компилятор Си года 90-го и последний Java — и тому, и тому лет по 20 будет. Равные условия? На кого поставите?
                                                                                            –1
                                                                                            Не равные, последний компилятор Java использует знания накопленные за всё время, а Сишный только те что были до 90го года.
                                                                                            И в статье же про недостатки высокоуровневых языков вроде java. Если взять какой-нибудь Си и запихать его в рантайм с jit'ом, то он сможет выдать точно такой же код, как и обычный компилятор.
                                                                                  0
                                                                                  Да все нормально, ну нельзя сделать memcpy в Java так же быстро как на Си — что из этого, панику устраивать? А взамен Java дает безопасный код, который не падает в core. Unsigned конечно не хватает, я вообще слабо представляю причины, по которым нужно было отказываться от unsigned-типов. В C#, к примеру, это есть с самой первой версии.
                                                                                  Вообще мне кажется, что самое интересное из этого сообщения — то, что Google не склонен доверять Си-реализациям по сравнению с Java-реализациями до такой степени (несмотря на штат суперпрофессионалов), что даже переписывает сишный код на Java.
                                                                                    +1
                                                                                    Задача была написать реализацию, которая могла бы работать как плагин к Eclipse.
                                                                                    +7
                                                                                    По-моему любые попытки сравнивать языки разных групп — это чистейшей воды холивары, ибо java если и сравнивать, то тогда уж с C# или ещё каким-нибудь .NET. Есть места где лучше использовать языки типа java/C#/и т.д. в силу того что там идёт JIT-компиляция, которая, грубо говоря, адаптирует код под реальные данные и выжимает максимум, ну и, естественно, есть места, где без чистого C или (ещё глубже к железу) без ассемблера не обойтись.
                                                                                    Язык — это инструмент! Не будем же забивать микроскопами гвозди, гвозди закручивать отвёрткой и делать другие глупости. Каждой задаче — свой инструмент!
                                                                                      +1
                                                                                      Иногда лень (то есть ожидаемый профит меньше усилий) идти за молотком, да ещё учиться с ним обращаться. Не только как забивать, но и как его хранить и транспортировать :)
                                                                                        0
                                                                                        Если человеку лень «освоить молоток для забивания гвоздя» и он его закручивает отвёрткой или микроскопом заколачивает. то может забивание гвоздей не для него?
                                                                                          0
                                                                                          А что делать, если из-за одного гвоздя строительство целого дома останавливается? Тратить пару месяцев на осваивание «ентерпрайзного» молотка? А заказчик дома не против, чтоб я гвоздь отверткой забивал, хотя и предупрежден, что дверь будет не так быстро открываться, как могла бы, а может и вобще заклинить.
                                                                                            0
                                                                                            Обычно при отсутствии штатного специалиста по гвоздям просто нанимают такого. Это вполне нормально когда человек при отделке своего дома сталкивается с тем, что, например, не умеет класть плитку в санузле, так он и не рвётся учиться (как-никак один раз положить надо, а не миллион), ну и просто-напросто нанимает специалиста.
                                                                                              0
                                                                                              А вот это уже от многих критериев зависит. Например, есть ли смысл нанимать специалиста, если он возьмёт за работу в 10 раз больше стоимости плитки и сравнимо со стоимостью всего остального ремонта? Не проще ли на жидкие гвозди посадить?
                                                                                        +1
                                                                                        Кстати JIT компиляция может действительно ускорять все эти несовершенства. Если бы можно было плагины к JIT писать как в LLVM, думаю большинство проблем удалось бы оптимизировать именно этими плагинами.
                                                                                          0
                                                                                          Вообще да, но есть и другие случаи, как описанный автором статьи — когда нужно реализовать конкретную задачу, на конкретном языкы (например, из за ограничений инфраструктуры и/или среды). Логично, что задачу пытаютя решить максимально эфеективно в рамках данного языка и поставленых условий и логично, что будут сравнивать с другими, более эффективными решениями на других языках.
                                                                                          +5
                                                                                          Все сводится к одной простой фразе — гибкость в угоду легкости. Если бы в джаве был такой же контроль над кодом как в С то это была бы уже не джава. Что тут сравнивать, совершенно непонятно.
                                                                                            +1
                                                                                            И ни для кого не секрет что в джаве отсутствует ручное управление памятью. Джава не создавалась для написания системных приложений и разработки драйверов. Её стихия — энтерпрайз и кросплатформенные приложения, с поддержкой кучи фич о которых можно почитать в вики по запрому JavaEE. Грешить после этого что Джава медленне чем С это как-то… странно что ли )
                                                                                          • UFO just landed and posted this here
                                                                                              +1
                                                                                              Каждый массив в Java — уже объект и полноценный наследник Object.
                                                                                              А каждому объекту нужны всякие доп поля, например для GC, для определения класса итд.
                                                                                              • UFO just landed and posted this here
                                                                                                  0
                                                                                                  >Тогда первое, это касается только массивов из примитивных типов?
                                                                                                  Любой массив наследует Object

                                                                                                  >И второе, почему же использование int[5] тогда лучше использования byte[20]?
                                                                                                  Если честно — не знаю, возможно JIT разворачивает маленькие массивы в переменные. Для 5 это происходит а для 20 нет. Это лишь предположение, было бы интересно узнать реальную причину.
                                                                                                    +3
                                                                                                    Речь идет не о int[5]. Имеется в виду замена
                                                                                                    class GitObject {
                                                                                                        Data someData;
                                                                                                        byte[] digest;
                                                                                                    }
                                                                                                    

                                                                                                    на
                                                                                                    class GitObject {
                                                                                                        Data someData;
                                                                                                        int digest0;
                                                                                                        int digest1;
                                                                                                        int digest2;
                                                                                                        int digest3;
                                                                                                        int digest4;
                                                                                                    }
                                                                                                    

                                                                                                    Т.е. заинлайнить SHA1-дайджест прямо в поля класса. Отсюда экономия на лишнем объекте byte[] и ссылке на него.
                                                                                                    • UFO just landed and posted this here
                                                                                                  0
                                                                                                  В Java любой массив — это объект. И там хранится много служебной информации.http://habrahabr.ru/blogs/java/134910/#comment_4480266

                                                                                                  8 байт за заголовок объекта (первые 4 байта общая информация, вторые 4 байта указатель на класс), потом еще 4 байта — длина массива, + это все выравнивается по 8-байтной границе. Вот вам и дополнительные 16 байт.
                                                                                                  +7
                                                                                                  > Что характерно, JGit выполняет операцию rev-list --objects –all примерно вдвое дольше, чем это делает Git, на проекте вроде ядра Linux, а index-pack для файла размером около 270 МБ тоже длится примерно вдвое дольше.

                                                                                                  Хех. Уже этой фразы достаточно, чтобы не бояться и брать в руки Java :)
                                                                                                    0
                                                                                                    Git под Windows (msysgit) работает медленнее, чем Mercurial под тот же Windows. Ну и что, где тут скорость C по сравнению с Python?

                                                                                                    Плагин для Mercurial под Eclipse сам не оперирует файлами репозитория, а просто вызывает hg.exe. Ну и что? Получается вполне быстро.

                                                                                                    И скорость таких программ упрётся всё равно не в копании в byte[20], а скорость дисковых операций и доступа к сети.

                                                                                                    Миллионы сайтов работают на интерпретируемом PHP, и никто не парится что они не на скоростном C.
                                                                                                      +2
                                                                                                      It depends.
                                                                                                      >Git под Windows (msysgit) работает медленнее, чем Mercurial под тот же Windows. Ну и что, где тут скорость C по сравнению с Python?
                                                                                                      Сравнивать работу двух разных программ и сравнивать работу двух разных реализаций одной и той же программы на разных языках — это разные вещи. Особенно когда заведомо известно что обе реализации качественные и оптимизированные.
                                                                                                      >И скорость таких программ упрётся всё равно не в копании в byte[20], а скорость дисковых операций и доступа к сети.
                                                                                                      «JGit выполняет операцию rev-list --objects –all примерно вдвое дольше, чем это делает Git, на проекте вроде ядра Linux»
                                                                                                      дисковые операции одни и те же, однако
                                                                                                      >Миллионы сайтов работают на интерпретируемом PHP, и никто не парится что они не на скоростном C.
                                                                                                      Да Вы провокатор :) Миллионы сайтов могут сколько угодно работать на PHP и не париться об оптимизациях, пока у них 1-1000 посещений в день. Когда кол-во посещений исчисляется миллионами-миллиардами, приходится брать в руки профайлер и оптимизировать, или садиться и переписывать проблемные части на C.
                                                                                                      PHP программисты любят тыкать в сторону Facebook, но при этом забывают, что Facebook использует свой самописный «преобразователь исходного кода» HipHop который конвертит PHP в C++.
                                                                                                        0
                                                                                                        >PHP программисты любят тыкать в сторону Facebook, но при этом забывают, что Facebook использует свой самописный «преобразователь исходного кода» HipHop который конвертит PHP в C++.

                                                                                                        Что говорит о недостатках «нативного» транслятора, но не самого языка, потому люблю тыкать в Facebook и т. п., когда мне «намекают» на убожество PHP и невозможность строить на нём highload приложения :)

                                                                                                        Хотя, наверное, нативный C++ работал бы быстрее, да и при наличии соответствующих библиотек/фреймворков писать на нём было бы не сильно медленнее чем на PHP. Вряд ли там активно используется динамическая типизация (в смысле что переменные меняют тип в рантайме, даже на «визитках» смысла в этом мало обычно, а читаемость ухудшается, проще ансетнуть ненужную "$temp1" и «объявить» "$temp2", если расход памяти важен или просто показатья явно что переменная больше не нужна) и прочая «магия».

                                                                                                    Only users with full accounts can post comments. Log in, please.