【问题标题】:Are algorithm benchmarks in PHP pointless?PHP 中的算法基准测试毫无意义吗?
【发布时间】:2011-04-18 00:51:56
【问题描述】:

由于 PHP 对我来说更简单,我希望在其中对算法进行基准测试以获得乐趣,因此我选择了阶乘。

递归函数在我到80!的时候速度完全不如迭代法,然后逐渐暴涨,而迭代法有一条稳定的线,实际上是这样的(x = factorial, y = seconds ):

但是在 C/Java 中(我刚刚在其中实现了测试)显示相同的结果,彼此之间只有 1-5% 的折扣,几乎相同的速度。

在脚本语言中以这种方式对算法进行基准测试是没有用的吗?

编辑:对于 NullUserException:

function factrec($x) {
    if($x <= 1) {
        return $x;
    } else {
        return $x * factrec($x - 1);
    }
}

【问题讨论】:

  • 如果递归版本比迭代版本差很多,那么你就执行了阶乘错误。
  • @NullUserException:我编辑了我的帖子,向您展示了它的普通代码。我设置了输出缓冲 (ob_start()) 并在回显它的 10000000 个结果和迭代后刷新它。
  • 如果我记得,PHP 中的递归非常慢,所以这可以解释这里的区别。
  • 查看我对阶乘尾递归版本的回答

标签: php performance algorithm scripting-language


【解决方案1】:

Java 和 C 比 PHP 快几个数量级。
您需要显着增加输入大小才能看到结果。

此外,正如 Aaron McSmooth 所说,用您计划使用的语言以外的语言对算法进行基准测试是没有意义的。

我不确定,但我怀疑 PHP 是否会进行尾调用优化。 无论如何,使用尾递归函数应该会大大提高递归函数的性能:

function factorial($n, $product) {
    if ($n < 1)
        return $product;
    else
        return factorial($n-1, $product*$n);
}

print(factorial(80, 1));

【讨论】:

  • 您可以肯定:PHP 不做尾调用优化。但是,是的,你可以蹦床。
  • 嗯,该函数产生了这些结果(使用的阶乘增加):iter: 1.315s rec: 4.069s iter: 1.861s rec: 7.32s iter: 2.951s rec: 13.863s iter: 4.993s rec: 26.769s iter: 9.569s rec: 53.639s 由于某种原因变慢了。
【解决方案2】:

考虑到练习的重点很有趣,它不可能毫无意义!但是尝试让 PHP 执行递归计算可能表明您已经准备好尝试函数式编程语言了。你见过哈斯克尔吗?尾调用优化,有人吗?

来吧,加入黑暗面。

【讨论】:

【解决方案3】:

用脚本语言对算法进行基准测试绝对不是毫无意义的。完成基准测试后,您会在 PHP 中使用哪种阶乘实现? (假设由于某种原因你不能使用内置的。)

用一种语言进行基准测试是毫无意义的,这种语言的特性与你想要实现算法的语言有很大不同。在这里,PHP 中函数调用和if 语句的相对成本显着扭曲了结果(或者这是我最好的猜测)。如果您仔细了解为什么会发生这种情况并避免它,那么它仍然可以取得丰硕成果:您注意到差异会更加夸张。归结为用目标语言编写或解决差异是否更容易。

算法复杂度的简单计算应该足以决定使用哪一个,或者至少缩小选择范围。


正如 Mike Axiak 在 cmets 中指出的那样,您甚至没有在这里测试不同的算法,而是在测试同一算法的两种不同实现:将运行产品保持在 in1。用与目标不同的语言来做这件事几乎总是毫无意义的。

【讨论】:

  • 并且需要注意的是,如果选择迭代或递归实现,算法复杂度不会改变。
  • @Mike Axiak。那是个很好的观点。我什至会明确说明您的含义,并说在这种情况下它们甚至不是不同的算法。
  • 我喜欢所有这些答案。完全有意义的是,(脚本语言)中的每个元素都会增加脚本的复杂性及其工作方式,这可能会掩盖算法的真实性能,从现在开始我将只对 php 与 php 函数进行基准测试,并使用对其他人来说更强大的东西。
【解决方案4】:

您遇到了 PHP 递归能力差的问题。人们通常不会选择 PHP 来做这种事情。始终为工作选择最佳工具。

【讨论】:

    【解决方案5】:

    基准测试从来都不是毫无意义的。如果您有一些以任何语言编写的代码,这对您的应用程序来说太慢了,那么您就会找出瓶颈。查看这些瓶颈,您会寻找解决方案。一种解决方案可能是使用不同的算法公式,甚至用不同的语言重写。

    我对PHP一无所知,所以我不知道在那种环境中递归是否处理得很好,但我的印象是它不是实现繁重重复数学的好选择......

    【讨论】:

      【解决方案6】:

      递归与迭代实现对特定算法的渐近行为应该没有实际影响。在某些语言(scala、Scheme、Lua、Standard ML、Mozart/Oz、erlang)中,两者实际上可以写成完全相同。即如下方案代码:

      (define factorial
        (lambda (n acc)
          (if (= n 0) acc
              (factorial (- n 1) (* n acc)))))
      (factorial 5 1)
      -> 120
      

      不会使用堆栈,因此执行与迭代方法相同的操作。 (这称为尾调用优化,在执行尾递归时以这种语言调用。)

      【讨论】:

      • +1,我希望在基准的 Java 实现中测量尾递归以测试 PHP 的结果,但不幸的是我的 jvm 不支持它。
      【解决方案7】:

      在我看来,如果我要测试算法本身,我会选择 C/C++,以获得它可以在最佳条件下提供的“原始力量”。

      另一方面,如果我必须选择哪种算法在某种条件下效果最好,我会尽量复制这种条件。它必须放在 PHP 应用程序中吗?让我们在 PHP 中使用 PHP 提供的结构对其进行测试。它是否需要与 STL 容器一起使用?我将在这种情况下进行测试,而不仅仅是使用数组。恕我直言,在真实条件下进行测试是获得有意义结果的关键。得到这样的结果后,另外一个好办法就是对这样的条件进行微调(只要你能在项目中改变它们),看看你得到了什么效果,找到最佳的条件-算法对。

      【讨论】:

      • 我相信 OP 的目的是对 脚本语言(在本例中为 PHP)以及它们在实现计算密集型算法方面的表现进行基准测试。
      • 我认为这是一个问题:“在脚本语言中以这种方式对算法进行基准测试是没有用的吗?”我的意见是:不,如果那样的话,你必须在这样的语言中使用它们。 :)
      猜你喜欢
      • 2015-04-30
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 2014-12-27
      • 2010-09-11
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      相关资源
      最近更新 更多