Подтвердить что ты не робот

Что быстрее? ++, + = или x + 1?

Я использую С# (этот вопрос также применим для подобных языков, таких как С++), и я пытаюсь найти самый быстрый и эффективный способ увеличения. Это не один или два приращения, в моей игре, как 300 приращений в секунду. Как и Рамки каждого спрайта на экране увеличиваются, скорость и положение моего символа rpg, смещение камеры и т.д. Поэтому я думаю, какой способ наиболее эффективен? например, для увеличения 5 y_pos для каждого движения, которое я могу сделать:

1.

Player.YPos += 5;

2.

Player.YPos = Player.YPos + 5;

3.

for (int i = 0; i < 5; i++)
{
    Player.YPos++;
}

Какой самый эффективный (и самый быстрый)?

4b9b3361

Ответ 1

(Ответ, специфичный для С# как С++, может значительно различаться.)

1 и 2 эквивалентны.

3 определенно будет медленнее.

Сказав, что, делая это всего 300 раз в секунду, вы не заметите никакой разницы. Знаете ли вы, сколько компьютеров может сделать с точки зрения необработанного процессора + памяти за секунду? В общем, вы должны написать код для ясности как самое важное. Во что бы то ни стало беспокоиться о производительности - но только тогда, когда у вас есть способ его измерить, чтобы: а) указать, нужно ли вам беспокоиться, и б) повлияли ли какие-либо изменения на производительность.

В этом случае я бы сказал, что вариант 1 является самым ясным, так что я бы использовал.

Ответ 2

Варианты 1 и 2 приведут к созданию идентичного кода компилятором. Вариант 3 будет намного медленнее.

Это ошибка, что i++ быстрее, чем i += 1 или даже i = i + 1. Все достойные компиляторы превратят эти три инструкции в один и тот же код.

Для такой тривиальной операции, как добавление, напишите самый чистый код и дайте компилятору беспокоиться о том, чтобы сделать его быстрым.

Ответ 3

Компилятор должен создать ту же сборку для 1 и 2, и она может развернуть цикл в варианте 3. Когда вы сталкиваетесь с подобными вопросами, полезным инструментом, который вы можете использовать для эмпирического тестирования того, что происходит, является просмотр собранной сборки компилятором. В g++ это может быть достигнуто с помощью переключателя -S.

Например, оба варианта 1 и 2 создают этот ассемблер при компиляции с помощью команды g++ -S inc.cpp (с использованием g++ 4.5.2)


main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    addl    $5, -4(%rbp)
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

g++ создает значительно менее эффективный ассемблер для опции 3:


main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    $0, -8(%rbp)
    jmp .L2
.L3:
    addl    $1, -4(%rbp)
    addl    $1, -8(%rbp)
.L2:
    cmpl    $4, -8(%rbp)
    setle   %al
    testb   %al, %al
    jne .L3
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

Но с оптимизацией на (даже -O1) g++ производит это для всех 3 вариантов:


main:
.LFB0:
    .cfi_startproc
    leal    5(%rdi), %eax
    ret
    .cfi_endproc

g++ не только разворачивает цикл в опции 3, но также использует инструкцию lea для добавления в одну команду вместо того, чтобы faffing about with mov.

Таким образом, g++ всегда будет создавать одну и ту же сборку для опций 1 и 2. g++ будет создавать одну и ту же сборку для всех 3 опций, только если вы явно включите оптимизацию (это поведение, которое вы, вероятно, ожидаете).

(и похоже, что вы должны проверить сборку, выпущенную С#, хотя я никогда не пробовал это)

Ответ 4

Они одинаковы:

static void Main(string[] args)
{
    int a = 0;
    a++;
    a +=1;
    a = a+1;
}

Вышеприведенный код в ILSpy:

private static void Main(string[] args)
{
    int a = 0;
    a++;
    a++;
    a++;
}

Кроме того, IL для всех этих программ также является таким же (в режиме Release):

.method private hidebysig static void  Main(string[] args) cil managed
{
    .entrypoint
    // Code size       15 (0xf)
    .maxstack  2
    .locals init ([0] int32 a)
    IL_0000:  ldc.i4.0
    IL_0001:  stloc.0
    IL_0002:  ldloc.0
    IL_0003:  ldc.i4.1
    IL_0004:  add
    IL_0005:  stloc.0
    IL_0006:  ldloc.0
    IL_0007:  ldc.i4.1
    IL_0008:  add
    IL_0009:  stloc.0
    IL_000a:  ldloc.0
    IL_000b:  ldc.i4.1
    IL_000c:  add
    IL_000d:  stloc.0
    IL_000e:  ret
} // end of method Program::Main

Ответ 5

Варианты 1 и 2 приведут к идентичному коду после компиляции. Вариант 3 будет намного медленнее, поскольку его результаты приводят к большему количеству кода для задействованного цикла.