Andy Melnikov (nponeccop) wrote,
Andy Melnikov
nponeccop

Category:

Почему Си не тормозит, в отличие от - технические причины

Чистота, высокоуровневость и сборка мусора играют на руку другим языкам, но по итогам преимущества Си в плане производительности перевешивают недостатки.

Эффект от чистоты, кстати, не настолько большой - что GCC, что SLang внутри используют SSA (относительно чистое промежуточное представление).

1. Более зрелый оптимизатор

Это прямое следствие политических причин.

2. Экономия тегов и боксов

Боксы (к примеру, идея хранить в конс-ячейке списка не значение, а указатель на него) вредят не только раздуванием кучи, но и нагрузке на подсистему памяти (pointer chasing). Оверхед от произвольного доступа к памяти в современных системах очень велик.

Сюда же идёт замена первоклассного полиморфизма инстанцированием.

3. Энфоршение линейного стиля с доступом через единственный указатель

В Си на структуру есть один "постоянный" указатель - на корень дерева, начало списка, "начальный" узел в графе и т.п. и статически известное количество "текущих" указателей. Если писать по-другому - просто не получится ручное управление памятью. Обычно этот момент упускается, но он имеет столь же неочевидно далеко идущие последствия, как безболезненность бета-конверсий в Хаскеле. А персистентные структуры, скажем, энфорсят прямо противоположный стиль.

4. Экономия аллокаций в куче

RVO, отказ от решения Funarg problems, RAII - всё сделано для поощрения аллокации на стеке. Тут опять же идёт припирание программиста к стенке: будешь писать по-другому - производительность будет в жопе. Для сравнения, тот же хаскель аллоцирует в куче по нескольку ячеек на каждый чих. И только если убогий оптимизатор изредка сработает - будет стек.

Стек, кстати, тоже способствует локализации и как следствие - уменьшению нагрузки на шину памяти.

5. Неидиоматичность абстракций управления

Наличие ФВП серьёзно затрудняет dataflow analysis и, как следствие, оптимизацию. Тенденция внутри компилятора инлайнить всё, что только можно, и тенденция программиста заменять функцию-аргумент флагом (т.н. дефункционализация по Рейнольдсу) приводят к повышению производительности (с ветвлением суперскалярный предсказатель ветвлений справляется лучше, чем с косвенным переходом)

Это всё, имхо, имеет мало общего с наивным представлением о "близости Си к ассемблеру". Да, Си можно минимальными усилиями транслировать оператор-в-инструкцию, но... производительность будет в жопе. Так, адресная арифметика давно уже не в почёте процом, SSE невыразимо без интринсиков, аналогично армовские инструкции с флагом ветвления, и т.п. gcc уже довольно давно уделывает по кодогенерации ассемблерного программиста, не обложившегося vTune и Intel Optimization Reference Manual.

Низкоуровневость - да, есть, но в основном в возможности экономить 5 вышеозначенных вещей: алиасинг, оверхед хранения, оверхед pointer chasing, аллокации в куче, статически непредсказуемые косвенные переходы.
Tags: fp, programming
Subscribe

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 55 comments