Что такое встраивание? - PullRequest
       32

Что такое встраивание?

24 голосов
/ 10 октября 2009

Я имею в виду это обсуждение . Я никогда не писал код на C или C ++. У меня нет никакого CS фона. Тем не менее, я работаю разработчиком Java уже 5 лет, и теперь я решил узнать больше о CS и немного наверстать упущенное.

Ответы [ 10 ]

37 голосов
/ 10 октября 2009

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

Inlining решает проблему производительности и ремонтопригодности, позволяя вам объявить функцию как inline (по крайней мере, в C ++), так что при вызове этой функции - вместо использования вашего приложения прыжок во время выполнения - код встроенной функции вставляется во время компиляции каждый раз, когда вызывается данная функция.

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

12 голосов
/ 10 октября 2009

http://en.wikipedia.org/wiki/Inlining

В вычислениях, встроенное расширение или встраивание - это оптимизация компилятора, которая заменяет сайт вызова функции телом вызываемого. Эта оптимизация может улучшить использование времени и пространства во время выполнения за счет возможного увеличения размера конечной программы.

7 голосов
/ 10 октября 2009

Как разработчику Java, вам, как правило, не нужно беспокоиться о методе встраивания. Компилятор Java Just-in-time может и будет делать это автоматически в большинстве мест, где это имеет смысл.

В IDE, таких как eclipse, может быть функция, позволяющая вам встроить методы на уровне исходного кода - никогда делают это для производительности, только для удобства чтения кода (например, когда вы понимаете, что метод просто вызывает друг друга метод без добавления ничего полезного сам по себе).

2 голосов
/ 06 декабря 2018

Норман Маурер объясняет в своем блоге встроенную функциональность JVM и JIT вот так

Встраивание - это метод, который в основном просто «встроит» один метод в другой и избавит от вызова метода. JIT автоматически обнаруживает «горячие» методы и пытается встроить их для вас. Метод считается «горячим», если он был выполнен больше X раз, где X - это порог, который можно настроить с помощью JVM флаг при запуске Java (по умолчанию 10000). Это необходимо, поскольку встраивание всех методов принесет больше вреда, чем что-либо еще, из-за огромного количества создаваемого байт-кода. Кроме того, JIT может «возвращать» предыдущий встроенный код, когда оптимизация оказывается неправильной в более позднем состоянии. Помните, что JIT расшифровывается как Just in Time, поэтому оптимизируйте его (включая встраивание, но и другие вещи), пока выполняете ваш код.

Также с предупреждением

Но даже если JVM считает метод «горячим», он может не встроить его. Но почему? Одна из наиболее вероятных причин состоит в том, что слишком велико, чтобы быть встроенным.

И вы можете найти очень простой пример кода для встраивания кода Java в Eva Andreasson Java World Post . Вы можете найти соответствующую часть сообщения ниже.

Многие оптимизации пытаются исключить инструкции перехода на уровне машины (например, JMP для архитектур x86). Инструкция перехода изменяет регистр указателя команды и тем самым передает поток выполнения. Это дорогостоящая операция по сравнению с другими инструкциями ASSEMBLY, поэтому она является общей целью сокращения или устранения. Очень полезная и общеизвестная оптимизация, которая нацелена на это, называется встраиванием. Поскольку прыжки стоят дорого, может быть полезно встроить много частых вызовов небольших методов с разными адресами входа в вызывающую функцию. Код Java в листингах с 3 по 5 иллюстрирует преимущества встраивания.

Листинг 3. Метод вызова

int whenToEvaluateZing(int y) {
   return daysLeft(y) + daysLeft(0) + daysLeft(y+1);
}

Листинг 4. Вызываемый метод

int daysLeft(int x){
   if (x == 0)
      return 0;
   else
      return x - 1;
}

Листинг 5. Встроенный метод

int whenToEvaluateZing(int y){
   int temp = 0;

   if(y == 0) temp += 0; else temp += y - 1;
   if(0 == 0) temp += 0; else temp += 0 - 1;
   if(y+1 == 0) temp += 0; else temp += (y + 1) - 1;

   return temp; 
}

В листингах с 3 по 5 метод вызова выполняет три вызова маленький метод, который мы предполагаем, что в этом примере больше выгоднее встроить, чем прыгать до трех раз.

Возможно, не имеет большого значения встроить метод, который вызывается редко, но встраивая так называемый «горячий» метод, который часто Вызов может означать огромную разницу в производительности. Также часто уступает место дальнейшей оптимизации, как показано в листинге 6.

Листинг 6. После встраивания можно применить дополнительные оптимизации

int whenToEvaluateZing(int y){
   if(y == 0) return y;
   else if (y == -1) return y - 1;
   else return y + y - 1;
}
2 голосов
/ 10 октября 2009

Как уже упоминалось в других ответах, встраивание идет со стоимостью. Обычно это считается небольшим, однако при фактическом измерении вы можете быть удивлены и узнаете, что оно может быть больше, чем то, что вы получаете (поэтому то, что другие люди говорят , верно: не оптимизируйте, если вы не измерили).

Стоит отметить, что некоторое время назад в ядре Linux они начали разжимать встроенные функции, потому что их стоимость была слишком высока (более крупные функции потребляли больше кеш-памяти процессора, а возникающие в результате ошибки кеша были дороже, чем просто вызов функции, которая должна была быть встроенной). См. «Глава 15: Болезнь в линии» в doc / Documentation / process / coding-style.rst для получения более подробной информации.

0 голосов
/ 10 октября 2009

Встроенные функции обычно используются в заголовочных файлах C ++, а не в Java. Заголовочный файл C ++ обычно не содержит реализованный код и считается интерфейсом с одноименным файлом cpp, который обычно содержит реализованный код. В заголовочный файл разрешено включать встроенную функцию, обычно небольшую облегченную функцию. Встроенные функции стоят дорого, поэтому они не должны быть большими операциями, интенсивно использующими память. Для небольших подпрограмм снижение производительности минимально, и они больше используются для удобства.

0 голосов
/ 10 октября 2009

В этом обсуждении Jon Skeet упоминает Client jvm (hotspot) v Server jvm с улучшениями производительности, доступными во время выполнения, если компилятору JIT (точно в срок) разрешено вносить усовершенствования, основанные на времени. Вот как это делается в Java.

Изначально небольшие фрагменты кода, которые не вызывались из многих мест, были бы "встроены" компилятором, то есть то, что было названо синглтоном, было бы помещено непосредственно в путь кода указателя инструкций, выполняя ветвь функции и возвращая затраты. больше мощности процессора, чем просто развертывание цикла или вызов функции и размещение инструкций "прямо там"

Сегодня Синглтон является предметом многостраничных обсуждений и развертывания циклов, а также что-то вроде вставки, которые несколько удалены из их первоначального контекста (ов). Вы можете прочитать очень информированную работу Дов Булька по этому вопросу, чтобы понять, как это делает C / C ++. Что касается Java, изучение его богатых библиотек в java.util лучше послужило бы вашим потребностям, чем изучение встраиваемых и глубоких проблем компилятора - вы можете зацепиться за укоренившуюся внутреннюю войну в боевых условиях в структурах данных, которые затушевывают вызовы в 16-битный код, не зацикливайтесь на своей кривой обучения.

Вы можете сделать instanceof в Java, который напоминает vf-таблицу (не жарко, пожалуйста), но думайте об этом, как будто вы писали на строго типизированном языке - и теперь будете писать на языке, где строка может быть убегающей легко ковыряться там, где нет бизнеса. Недавно я пытался написать код, который сконструировал изображение на Java, делая это из кода на Си. Вскоре я обнаружил, что смотрю на таблицу oxr для надежного шифрования - это не имеет ничего общего с кодом, который я писал.

Как бы вы написали строковый класс в C / C ++, который имеет небольшой буфер для строк длиной до 32 байт и перехватывает указатели, чтобы они работали только со строкой?

Не пытаясь дразнить вас или что-то еще, это просто хорошее место для начала, а не встраивание и компиляция науки.

0 голосов
/ 10 октября 2009

Ответы по оптимизации компилятора верны. Однако есть и другое применение - в рефакторинг под вставкой подразумевается замена вызова метода телом метода, а затем удаление метода. См. Встроенный метод . Существуют похожие рефакторинги, такие как Inline Class .

РЕДАКТИРОВАТЬ: обратите внимание, что рефакторинг выполняется вручную или с помощью инструмента; в любом случае это связано с изменением исходного кода.

0 голосов
/ 10 октября 2009

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

0 голосов
/ 10 октября 2009

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

Это будет более подробно: http://www.codersource.net/cpp_tutorial_inline_functions.html

...