C: Возвращает ли значение из функции больше циклов процессора, чем void?

Обычно я делаю общую фильтрацию по строкам следующим образом:

criterion = lambda row: row['countries'] not in countries
not_in = df[df.apply(criterion, axis=1)]
1
задан ZenJ 13 July 2018 в 22:22
поделиться

4 ответа

В системе x86_64 обе функции могут быть скомпилированы в один и тот же код. Я «замаскировал» разборку примерно эквивалентным кодом C:

f_or_g:
    pushq   %rbp                 ; // Standard stack frame setup
    movq    %rsp, %rbp           ; // same
    movl    OFFSET1(%rip), %eax  ; eax = c;
    addl    OFFSET2(%rip), %eax  ; eax += b;
    movq    OFFSET3(%rip), %rcx  ; rcx = &a;
    movl    %eax, (%rcx)         ; *rcx = eax;
    popq    %rbp                 ; // Standard stack frame teardown
    retq                         ; return

Так как x86_64 использует eax в качестве возвращаемого регистра для 32-битных значений, результат добавления находится в «правильном» place ", чтобы вернуть его уже - дополнительный код не требуется.

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

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

3
ответ дан duskwuff 17 August 2018 в 12:07
поделиться
  • 1
    Правильно ли я понял, что любой процессор, который использует eax (или аналогичный, я думаю, извините, если я просто сказал какую-то глупость!) Не потребует дополнительного кода? – ZenJ 13 July 2018 в 22:20
  • 2
    Это в основном зависит от того, какое значение вы возвращаете, это последнее, что вы вычислили в функции, поэтому оно может гарантировать, что вычисление приведет к его результату в том же регистре. – Barmar 13 July 2018 в 22:44
  • 3
    @ZenJ Точное имя регистра не имеет значения. Единственным действительно важным фактором является то, что в соглашении о вызове архитектуры используются регистры для возвращаемых значений (большинство из них), и что для архитектуры не требуются определенные регистры для конкретных операций (большинство из них: x86_64 делает немного, но это не так здесь вступают в игру). – duskwuff 13 July 2018 в 22:51
  • 4
    @Barmar Это не должно быть значение last ; просто должно быть достаточно доступных регистров, что любая работа "после & quot; расчет возвращаемого значения может быть выполнен без касания регистра возврата. – duskwuff 13 July 2018 в 22:52
  • 5
    Не могли бы вы включить информацию из комментариев в ответ? Я думаю, что они действительно повышают ценность. – ZenJ 17 July 2018 в 22:50

Я не думаю, что этот вопрос имеет смысл.

Если вы нуждаетесь в возвращенном значении, у вас нет возможности использовать void для его ускорения up, даже если будет быстрее. Если вам не нужен результат , бесполезно возвращать его, поэтому просто не делайте этого. В любом случае выбор определяется потребностями вызывающего абонента.

Как правило, современные компиляторы не возвращают значение, а создают его на месте. Например, если вы пишете int sum = f(a,b);, компилятор никогда не сделает временную функцию, а вместо этого сохранит результат в памяти sum. Это означает, что нет никакой разницы во времени выполнения.

3
ответ дан Aganju 17 August 2018 в 12:07
поделиться
  • 1
    На самом деле иногда это может пригодиться: например, если функция изменяет некоторые глобальные переменные или переменные-члены класса, но возврат не требуется в каждом месте, где используется функция. Но независимо от того, что я хотел бы применить свой вопрос только к совершенному миру «академических знаний», так что в основном это «что, если», вопрос, который может не иметь практического значения. Я прошу прощения за то, – ZenJ 13 July 2018 в 22:29
  • 2
    В примере вашего примера компилятор знает, когда вы используете результат, а когда нет, и строит его на месте, когда вы его используете, и никогда не возвращает его, если вы его подбрасываете. Другими словами: если вы определяете возвращаемое значение и никогда не используете его нигде, он просто никогда не возвращается, поэтому нет никакой разницы. – Aganju 13 July 2018 в 22:30

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

0
ответ дан hameed kunkanoor 17 August 2018 в 12:07
поделиться

Это полностью зависит от набора команд процессора и вызовов.

Если, например, возвращаемое значение всегда возвращается в конкретном регистре, и компилятор может организовать результат вычисления b + c, чтобы быть в этом конкретном регистре перед вставкой команды возврата, код, сгенерированный для этих двух функций, может быть идентичным.

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

5
ответ дан Timbo 17 August 2018 в 12:07
поделиться
  • 1
    Я полностью согласен, что это не то, как нужно оптимизировать код. Мой интерес здесь носит чисто академический характер, и я не ожидаю получить повышение производительности от изучения того, как обрабатываются возвращаемые значения. – ZenJ 13 July 2018 в 22:32
Другие вопросы по тегам:

Похожие вопросы: