这更有效,循环或只是定期添加

时间:2015-12-23 06:31:40

标签: c performance for-loop

我正在开发一个c应用程序,它从mysql表中读取数据,处理它然后将其插入到oracle数据库中的100个不同的表中。问题在于应用程序的性能存在巨大问题。在我提到的mysql表中,有4,800,000个,其中有92列。 90个主题只是整数。因此,在我的应用程序中,每个条目为4,800,000,我正在运行for循环,如下所示。

    for (col = 1; col < 92; col++) {
        if (row[col] != NULL) {
            sum += strtol(row[col], NULL, 10);
        } else
            sum = sum + 0;
        if (col == 14) {
            p1_2weeks = sum;
        } else if (col == 31) {
            p2_1month = sum;
        } else if (col == 90) {
            p3_2month = sum;
        }
    }

因此,由于这会进行大量迭代,所以我认为可能会减少使用常规添加所需的时间来完成此操作。

 p1_2weeks = strtol(row[1], NULL, 10) +
             strtol(row[2], NULL, 10) +
             ... +
             strtol(row[14], NULL, 10);
 p2_1months = p1_2weeks +
             strtol(row[15], NULL, 10) + 
             ... +
             strtol(row[31], NULL, 10);
 p3_3months = p2_1months +
             strtol(row[32], NULL, 10) +
             ... +
             strtol(row[91], NULL, 10);

所以有人可以建议哪一个更好或者其他一些方法做得对。

4 个答案:

答案 0 :(得分:7)

使用显式添加的for循环或手动展开不会产生显着差异。大部分时间都花在从MySQL读取并将字段转换为字符串,并将结果插入Oracle中。如果程序花费99%的时间在数据库代码中,这不会让我感到惊讶,优化这个循环将是一个没有实际意义的点。

您可能希望寻找一种从MySQL中提取不会将整数转换为字符串的值的不同方法。

分析将告诉您编译器/选项/ cpu / memory / dataset的给定组合的瓶颈在哪里,但是告诉您在程序中花费的时间以及等待Oracle进程或MySQL连接所花费的时间可能会很棘手。经过的时间是最终的判断。

请注意,您提议的替代方法在语义上不等效:在显式添加的序列中,您不测试NULL字段。如果列不能为NULL,则可以删除if (row[col] != NULL)测试,如果它们可以是NULL,则必须修改添加以添加更多测试,这将使其非常笨拙。此外,正如seleciii44所暗示的那样,提出的替代方案会生成更大的代码,这也会产生影响。

节点也认为循环非常简单,而添加的顺序容易出错:很容易产生剪切和粘贴错误并错过索引或重复索引。如果你去添加,请使用代码布局,使索引清晰。看看我如何重新格式化你的代码。

确实你在循环中有拼写错误(p2_1month / p2_1monthsp3_2month / p3_3months)并且添加不会以同样的方式计算p3_3months:循环总和90天,其中加法总和为91天。但当然,一个季度的天数从8992天不等。

另请注意,sum = sum + 0;是一个应删除的无操作,但编译器很可能不会为其生成代码。

如果您担心每次迭代执行14,31和90天的额外测试,您可以使用:

    long temp[92];
    for (col = 1; col < 92; col++) {
        if (row[col] != NULL) {
            sum += strtol(row[col], NULL, 10);
        }
        temp[col] = sum;
    }
    p1_2weeks = temp[14];
    p2_1month = temp[31];
    p3_3months = temp[90];

它可能比带有测试的版本更有效,但只有仔细的基准测试才会告诉您,因为现代处理器的分支预测会在将91值存储到本地数组中时将这些测试的成本降至最低额外费用。

顺便问一下,您确定col < 92吗?您的循环会处理91列,但您写的只有90列的92是整数。

同样,我首先会寻找一种从MySQL中提取值作为整数的方法。

答案 1 :(得分:4)

我不认为自己编写附加内容会让这更快。但优化不是通过猜测进行的,而是通过测量进行的。

我对您的代码的评论是:

else
   sum = sum + 0;

我希望你的编译器摆脱这个东西,否则你只是在这里浪费时间。

        if (col == 14) {
            p1_2weeks = sum;
        } else if (col == 31) {
            p2_1month = sum;
        } else if (col == 90) {
            p3_2month = sum;
        }

虽然分支预测可以在这里帮到你很多,但也许最好将它移出for-loop。你可以在几个循环中分离,中间的每个部分计算。 (循环到14,分配p1_2weeks,循环到31,保存p2_1个月...)

答案 2 :(得分:3)

对这样的问题唯一合理的答案是对其进行分析。以最直观的方式编写它,然后看看它是否值得花费大量时间来优化并调试所有优化。

答案 3 :(得分:2)

展开循环可以通过消除循环开销提供一个小优势,但是如果循环非常大并且其中的操作非常简单,在这种情况下都不是。

添加是非常简单的操作(一台机器指令),但是你错过了房间里的大象 strtol() - 你有一个函数调用开销加上将字符串转换为整数的任何内容,该整数将是许多机器指令(也在循环中)。

此外,如果有一些可能的显着优势,编译器优化器能够自行执行循环展开。因此,这种手写的微优化几乎总是徒劳的,并且使代码难以理解且难以维护。您最好考虑整体设计和算法复杂性,并让编译器执行 作业。

无论如何,鉴于这是一个数据库应用程序,它确实会在很大程度上受到磁盘和/或网络性能的限制,并且任何代码优化总体上可能无关紧要。快速的服务器和大量的RAM可能会比任何类型的代码优化更快地加速您的应用程序。