Когда в Rust следует использовать inline?


86

В Rust есть "встроенный" атрибут, который можно использовать в одном из этих трех вариантов:

#[inline]

#[inline(always)]

#[inline(never)]

Когда их следует использовать?

В справочнике Rust мы видим раздел встроенных атрибутов, в котором говорится

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

На форуме Rust internals huon также консервативно подходил к указанию inline .

Но мы видим значительное использование в исходном коде Rust, включая стандартную библиотеку. К однострочным функциям добавляется множество встроенных атрибутов, которые компиляторам должно быть легко обнаружить и оптимизировать с помощью эвристики в соответствии со ссылкой. На самом деле они не нужны?

Ответы:


70

Одно из ограничений текущего компилятора Rust заключается в том, что если вы не используете LTO (оптимизацию времени компоновки), он никогда не будет встраивать функцию, не отмеченную #[inline]в ящиках. Rust использует отдельную модель компиляции, аналогичную C ++, поскольку реализация LTO LLVM плохо масштабируется для больших проектов. Поэтому небольшие функции, доступные для других ящиков, необходимо маркировать вручную. Это не самая лучшая ситуация, и она, вероятно, будет исправлена ​​в будущем с помощью некоторой комбинации улучшений встраивания LTO и MIR.

#[inline(never)]иногда полезно для отладки (отделение части кода, который не работает должным образом). Теоретически его можно использовать для тестирования производительности, но обычно это плохая идея: отключение встраивания не предотвращает другие межпроцедурные оптимизации, такие как распространение констант. Что касается обычного кода, он может уменьшить размер кода, если у вас есть часто используемая вспомогательная функция, которая используется только для обработки ошибок.

#[inline(always)]вообще плохая идея; если функция достаточно велика, чтобы компилятор не встраивал ее по умолчанию, она достаточно велика, чтобы накладные расходы на вызов не имели значения (а чрезмерное встраивание увеличивает давление в кеш-память инструкций). Бывают исключения, но вам нужны измерения производительности, чтобы это обосновать. Этот пример заслуживает рассмотрения. #[inline(always)]также можно использовать для улучшения -O0качества кода, но обычно об этом не стоит беспокоиться.


19
обратите внимание, что inline(never)это используется во встроенных функциях паники, чтобы убедиться, что оптимизатор не встраивает функции, которые вызываются только в случае паники.
oli_obk 06

4
-1, потому что в первом пункте чего-то не хватает. Общие элементы могут быть встроены в крейты, поскольку они эффективно компилируются при создании экземпляров, поэтому код, необходимый для встраивания, легко доступен. А это значит, что огромное количество таких предметов, которые не промаркированы, все же могут быть встроены в кросс-ящик. В некоторых типах ящиков базовой библиотеки каждый элемент является универсальным!
bluss
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.