【问题标题】:What makes difference in computing time between (insertion sort using 'while') and (insertion sort using 'for')? [closed](使用'while'的插入排序)和(使用'for'的插入排序)之间的计算时间有什么区别? [关闭]
【发布时间】:2020-05-22 04:15:50
【问题描述】:
/////////////////////////////////////////////////////////////
void insertion_sort_f(int *A, int s, int e) {
    int j, i, tmp;
    for (j = s+1; j < e; j++) {
        tmp = A[j];     
        for (i = j - 1; i >= 0 && A[i] > tmp; i--)
            A[i+1] = A[i];          
        A[i + 1] = tmp;
    }
}
void insertion_sort_w(int *A, int s, int e) {
    int j, i, tmp;
    for (j = s + 1; j < e; j++) {
        tmp = A[j];
        i = j;
        while (--i >= 0 && A[i] > tmp) {
            A[i + 1] = A[i];
        }
        A[i + 1] = tmp;
    }
}
//////////////////////////////////////////////////////////////

我用 100000 个数据测试了两种插入排序,一种使用 'for',另一种使用 'while'。 我想计算时间没有有意义的差异。 但“while”比“for”平均快 1000 毫秒。 这个结果是哪一个?

ps。 我发布了完整的代码进行解释。 https://colorscripter.com/s/56xWn0O

【问题讨论】:

  • 您是否在启用编译器优化的情况下进行测试?我做了一些快速测试,两个函数之间没有显着差异。
  • @Blastfurnace 哦,你是对的!我将“调试”更改为“发布”,因此计算时间没有区别。谢谢~
  • 但我仍然不知道在“调试”模式下有何不同。
  • Debug == "故意放慢速度"。在调试版本中,每次修改变量时,它都会从寄存器中获取值,并将其写入内存位置。这样调试器就可以简单地查看内存地址来找出变量的当前值。
  • 我在调试模式下,编译器不会竭尽全力进行优化(例如删除不必要的操作、重新排序以提高性能)。如果你准确地写下你的代码所表达的操作序列,你会看到两个代码示例做不同的事情——即使它们对你的函数的调用者有相同的净效果。

标签: c++ c sorting


【解决方案1】:

如果将函数更改为:

void insertion_sort_w(int *A, int s, int e) {
    int j, i, tmp;
    for (j = s + 1; j < e; j++) {
        tmp = A[j];
        i = j - 1;
        while (i >= 0 && A[i] > tmp) {
            A[i + 1] = A[i];
            --i;
        }
        A[i + 1] = tmp;
    }
}

clang 和 gcc 将为这两种方法产生相同的输出。 https://godbolt.org/z/8Hzxys

使用您的原始实现,为这两种方法生成的 ASM 之间的差异很小。如果(进行优化!)两者之间有任何显着的性能差异,我会感到非常惊讶。

进一步了解 ASM:https://godbolt.org/z/Xo3hZ7

您的 while 循环版本确实产生更少的 ASM,然而这并不意味着它更快。这只是意味着编译器在for循环版本中生成了一些额外的代码块和跳转。这可能实际上会使 for 循环版本稍微快一些,因为它可能有一个额外的早期输出,而 while 循环版本没有。再说一次,额外的跳跃可能是一个问题。

使用诸如 vtune 之类的分析器可能是清楚了解相对性能的最佳选择。

【讨论】:

  • 我再次尝试了 3 类型插入排序(我的 2,你的 1)。我的'while'比别人快。你和我的“for”速度一样。
  • 我不相信你。您是在启用优化的情况下进行编译,还是在构建调试版本?
  • 调试模式。我发布了我的完整代码。我在visual studio中做了默认设置。 colorscripter.com/s/56xWn0O
【解决方案2】:

我可以看到有几件事会影响代码的实际执行时间。恕我直言,除非您正在编写特定于硬件的实时代码,否则我不会在性能上有很大差异。

  1. 编译器优化
    使用loop unrolling 可以优化分解循环。对于其中一种循环类型,编译器可能会更有效地执行此操作。
  2. CPU 优化
    在流水线 CPU 中,分支会损害性能。如果您查看为“for”或“while”循环生成的汇编代码,您将有一个条件分支命令(执行另一个迭代或在循环后继续编码)。简单来说,CPU不想等待条件分支的结果执行下一条命令,所以它“猜测”下一条命令,然后再决定是否丢弃结果(阅读Branch prediction和@ 987654323@).
    老实说,我不知道预测是否在一个循环或另一个循环上更有效,但这在理论上可以产生影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多