【问题标题】:PHP function efficienciesPHP函数效率
【发布时间】:2015-01-23 01:57:32
【问题描述】:

是否有一张表格说明在 PHP 中执行给定函数需要多少“工作”?我不是 Compsci 专业的,所以我可能没有正式的背景来知道“哦,是的,字符串比整数需要更长的时间”或类似的东西。程序中的所有步骤/行是否相同?我什至不知道从哪里开始研究这个。

我目前正在做一些 Project Euler 问题,我非常确定我的答案会奏效,但是我的请求会在一分钟内让我的本地 Apache 服务器超时(PE 说所有问题都可以解决question 206 代码:

<?php
$start = time();
for ($i=1010374999; $i < 1421374999; $i++) { 
$a = number_format(pow($i,2),0,".","");
$c = preg_split('//', $a, -1, PREG_SPLIT_NO_EMPTY);
if ($c[0]==1) {
    if ($c[2]==2) {
        if ($c[4]==3) {
            if ($c[6]==4) {
                if ($c[8]==5) {
                    if ($c[10]==6) {
                        if ($c[12]==7) {
                            if ($c[14]==8) {
                                if ($c[16]==9) {
                                    if ($c[18]==0) {
                                        echo $i;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
}
$end = time();
$elapsed = ($end-$start);
echo "<br />The time to calculate was $elapsed seconds";
?>

如果这是关于优化的 wiki 问题,请告诉我,我会移动它。同样,不是在寻找答案,只是帮助了解在哪里学习如何高效地编码(尽管粗略的提示不会被完全拒绝,而且我意识到可能有更优雅的数学方法来解决问题)

【问题讨论】:

  • 您最大的效率问题可能是您正在尝试蛮力解决方案。对于这类问题,没有多少代码可以使蛮力解决方案发挥作用。没有多少循环可以在一分钟内完成 4.11 亿次。与其试图挤进每秒更多的迭代,不如试着将你做的迭代次数减少几个数量级。
  • 对于这个问题,你应该看看平方数是如何工作的。例如mathworld.wolfram.com/SquareNumber.html。然后您会注意到平方根的最后两位数字只能是 30 或 70,这已经将您的搜索空间从 4.11 亿个数字减少到 8.220.000

标签: php performance optimization


【解决方案1】:

没有这样的表格可以告诉您每个 PHP 函数需要多长时间执行,因为执行时间会因输入而异。

看看你的代码在做什么。您已经创建了一个将运行 411,000,000 次的循环。鉴于代码需要在不到 60 秒(一分钟)内完成,为了解决您假设每次通过循环的行程将花费少于(大约)0.000000145 秒的问题。这是不合理的,再多的使用“正确”功能也无法解决您的问题。用 nothing 试试你的循环

for ($i=1010374999; $i < 1421374999; $i++) { 

}

除非您可以使用科幻计算机,否则这可能不会在 60 秒内完成。所以你知道这种方法永远行不通。

这是对问题的强力解决方案。 Project Euler 的目的是让您从数学和编程的角度创造性地思考问题。您希望减少需要通过该循环的行程次数。显而易见的解决方案永远不会是这里的答案。

我不想告诉你解决方案,因为这些事情的重点是思考你的方式并成为一个更好的算法程序员。检查问题,考虑它的限制,并考虑如何减少需要检查的数字总数。

【讨论】:

  • +1,这是解决“调试/配置文件问题”的绝佳方法:不要假设。要么测试/分析它(努力,如果你有一个“综合”测试更是如此)或者选择一个你可以做出明确声明的部分。我正要启动分析器,但......每个循环 .000000145 秒,案例关闭,我喜欢它;-)
  • 谢谢:A) 没有回答,B) 给出合理的提示,C) 没有假设我有一定的知识水平,但我没有。好答案!
【解决方案2】:

查看代码执行时间的好工具是 xDebug:http://xdebug.org/docs/profiler

这是一个可安装的 PHP 扩展,可以配置为输出脚本的函数调用和执行时间的完整分解。使用它,您将能够查看代码中执行时间最长的内容并尝试一些不同的方法。

编辑:现在我正在查看您的代码,您正在运行 4 亿多个正则表达式调用!我对 Euler 项目一无所知,但我很难相信这段代码可以在一分钟内在商品硬件上执行。

【讨论】:

  • 他的代码不能,但是有一个可以解决他的问题的方法。这就是这个欧拉项目的意义所在。可以在一分钟内编写求解器的数学问题。
  • 我对它做了一点研究。正如接受的答案中所述,这似乎是一个有趣的项目。
【解决方案3】:

preg_split 可能很慢,因为它使用的是正则表达式。有没有更好的方法来做那条线?

提示:您可以像这样访问字符串中的字符:

$str = 'This is a test.';
echo $str[0];

【讨论】:

    【解决方案4】:

    尝试将preg_split() 切换为更快的explode()str_split()

    【讨论】:

    • 好建议,但你怎么知道的?只是体验?正则表达式是否已知很慢?这是我不知道的更高层次的东西。任何帮助都很棒!
    • 是的,众所周知,正则表达式很慢。它们非常强大,可以很容易地查找/处理复杂的字符串,但这是有代价的。大多数时候它们都很好,但是在一百万次循环中这样做并不是那么有效。我不会试图解释它在内部是如何工作的(如果你真的想知道,你可以搜索谷歌)但我只想说它背后有一个完整的引擎来让所有的“魔法”发生:)
    • preg_split() 的文档说:“如果您不需要正则表达式的强大功能,您可以选择更快(尽管更简单)的替代方法,例如 explode() 或 str_split()。” php.net/preg_split
    【解决方案5】:

    首先,这里有一个更简洁的函数版本,带有调试输出

    <?php
    $start = time();
    $min = (int)floor(sqrt(1020304050607080900));
    $max = (int)ceil(sqrt(1929394959697989990));
    
    for ($i=$min; $i < $max; $i++) {
    $c = $i * $i;
    echo $i, ' => ', $c, "\n";
    if ($c[0]==1
        && $c[2]==2
            && $c[4]==3
            && $c[6]==4
            && $c[8]==5
            && $c[10]==6
            && $c[12]==7
            && $c[14]==8
            && $c[16]==9
            && $c[18]==0)
      {
        echo $i;
            break;
      }
    }
    $end = time();
    $elapsed = ($end-$start);
    echo "<br />The time to calculate was $elapsed seconds";
    

    这是输出的前 10 行:

    1010101010 => 1020304050403020100
    1010101011 => 1020304052423222121
    1010101012 => 1020304054443424144
    1010101013 => 1020304056463626169
    1010101014 => 1020304058483828196
    1010101015 => 1020304060504030225
    1010101016 => 1020304062524232256
    1010101017 => 1020304064544434289
    1010101018 => 1020304066564636324
    1010101019 => 1020304068584838361
    

    就在那里,它似乎应该激发您对算法的可能优化。请注意,从第 6 个条目 (1020304060504030225) 开始,我们甚至还没有接近——我们在需要 5 的位置获得了 6!

    事实上,许多下一个条目将一文不值,直到我们回到那个位置为 5 的点。为什么要费心计算中间值?如果我们能弄清楚怎么做,我们应该跳到 1010101060,那个数字又变成 5……如果我们能像这样一次跳过几十次迭代,我们将节省超过 90% 的运行时间!

    请注意,这可能根本不是一种实用的方法(事实上,我相当有信心它不是),但这是您应该考虑的方式。您可以使用哪些数学技巧来减少执行的迭代次数?

    【讨论】:

      猜你喜欢
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-09
      • 2011-11-20
      • 2014-03-22
      • 2014-11-23
      相关资源
      最近更新 更多