【问题标题】:Is any performance gained by using an if/else statement for an assignment?使用 if/else 语句进行赋值是否能获得任何性能?
【发布时间】:2019-08-18 08:21:43
【问题描述】:

我有一个简单的问题,我只是不确定。

考虑下面的代码:

#include <stdio.h>

static void turnOn(int *power);
static void turnOff(int *power);

int main(void)
{
    int powerIsOn = 0;


    turnOn(&powerIsOn);
    printf("Power Status: %d\n", powerIsOn);

    turnOff(&powerIsOn);
    printf("Power Status: %d\n", powerIsOn);

    return 0;
}


static void turnOn(int *power)
{
    if (!*power)
        *power = 1;
    // Or
    //*power = 1;
    return;
}

static void turnOff(int *power)
{
    if (*power)
        *power = 0;
    // Or
    // *power = 0;
    return;
}

我知道这不会对这么小的东西造成明显的影响。但是在进行某种赋值的方法中,在重新赋值之前检查布尔值或其他值是否已经是真/假是否更有效?

例如,turnOn() 功能设置为仅在电源关闭时才打开电源。不管值如何,将其设置为 1 会更慢还是更快?

感谢您的宝贵时间。

【问题讨论】:

  • 除非您在一个(外来)平台上,其中内存写入比内存读取成本很多,否则您很可能不会从这种“优化”中获得任何收益。它更有可能适得其反。

标签: c


【解决方案1】:

在任何情况下,您的代码都在访问内存,它在“if”内部执行,并且在您将其分配给 1 时执行。此外,“if”语句在二进制代码中添加了几行,所以如果您可以分配不使用“if”,更好更高效。

if (!*power)    #one memory access and addition if actions
    *power = 1; #one more memory access and assignment

查看编译后的汇编代码

static void turnOn(int *power)
{
    if (!*power)
        *power = 1;
    return;
} 

我们会看到下一段代码

turnOn:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        test    eax, eax
        jne     .L4
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], 1
        nop
.L4:
        nop
        pop     rbp
        ret

对于:

static void turnOn(int *power)
{
    *power = 1;
    return;
}

下一个代码:

turnOn:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], 1
        nop
        pop     rbp
        ret

在我看来,机器在第一种情况下会运行更多的操作。 我使用的是https://godbolt.org/ 编译器。

【讨论】:

  • 读取内存中地址的值与向其写入值是不同的操作。
  • 确实,但是,读取值需要访问内存。如果它可以幸免,那为什么不呢?执行 if 操作的附加操作可能比赋值操作花费更多,这取决于编译器。
  • 因为这取决于编译器将如何生成代码,我认为说“最好去掉检查”是不对的。除此之外,如果检查多次返回 false,它可以最终节省 cpu 周期,因为我认为这是 OP 所关心的。
  • 我编辑了答案,看看,也许它会说服你。
  • 好的,我接受你的说法。无论如何,我在我的计算机上检查了它并在 100000000 次迭代的循环上运行这两个变体并比较了时间。在我的电脑上,运行第一个变体平均需要 25.5 秒,运行秒数平均需要 21.1 秒,结果在测量之间保持非常相似。我接受不同的实现可能表现不同。对于这种特殊情况,我相信没有 if 会更好。
【解决方案2】:

这两个操作都涉及访问变量,因此依赖于内存管理。赋值涉及重新写入内存,因此比比较常量值(布尔值,或10)更“昂贵”。

话虽如此,对于现代硬件,这些差异可以忽略不计,因此不推荐使用 micro-optimizations

【讨论】:

  • 这完全取决于内存管理方法。它可能会提高运行时间,但我只会在有 很多 变量(相对于内存大小)的情况下使用它,但情况可能并非如此。
【解决方案3】:

我认为只能在特定场景下分析代码来回答。

如果编译器生成的代码直接读取值,那么在 C 中读取变量可以比为其赋值更有效(但这取决于给定编译器的实现)。

但是,要确定它是否执行得更快,这是间接的,例如如果这两个函数被顺序调用很多次,那么您创建的附加 if 语句将毫无用处,因为条件将始终返回 true 并将生成额外的指令(并且 CPU 将花费额外的时钟执行它们)来执行检查始终返回 true。我会说它确实需要进行分析并且取决于上下文。

【讨论】:

  • 阅读、比较和分配比简单分配更快?那将是一个有趣的系统...
  • 如果我们假设 OP 写的 if 语句可能比它的嵌入语句执行得更快,那么假设它是可能是合乎逻辑的最终执行速度更快。除非您暗示if 语句不能比其嵌入语句执行得更快;你是这么说的吗?
  • 没有。我的意思是几乎肯定不可能做到 A 然后 B 然后 C 比单独 C 更快。您的整个前提是可以比 C 更快地执行 A 然后 B 然后 C。仅仅因为不可能证明是否定的,我只是说你有一个巨大的举证责任要克服来证实你的主张。
猜你喜欢
  • 1970-01-01
  • 2011-11-17
  • 2021-02-23
  • 2020-01-20
  • 1970-01-01
  • 2011-12-06
  • 2013-09-01
  • 1970-01-01
  • 2022-12-07
相关资源
最近更新 更多