【问题标题】:PHP performance: if vs. assignmentPHP 性能:if 与赋值
【发布时间】:2011-07-04 01:54:37
【问题描述】:

我在这里发现了一个类似的问题: Performance: condition testing vs assignment

这个问题与优化无关。这是关于编码偏好。

这是一个例子:

我有我无法控制的数据。它来自第 3 方,以 db 表中的行的形式出现。这是 MSSQL SP 的结果。由于臃肿,我想在通过网络将数据作为 JSON 传输之前减小它的大小。由于大部分数据都是重复的,因此我可以将其缩小 80%。

所以我会这样做:

    $processed = array();
    foreach ($result as $row)
    {
        $id = $row['id'];
        $processed[$id]['title'] = $row['title'];
        $processed[$id]['data'] = $row['data'];
        $processed[$id]['stuff'] = $row['stuff'];
        /* many more assignments with different keys */

        $unique = array();
        $unique['cost'] = $row['cost'];
        /* a few more assignments with different keys */

        $processed[$id]['prices'][$row['date']] = $unique;
    }

我认为这可能会更快,但它看起来更慢(我计时了):

    $processed = array();
    $id = null;
    foreach ($result as $row)
    {
        if ($id != $row['id'])
        {
             $id = $row['id'];
             $processed[$id]['title'] = $row['title'];
             $processed[$id]['data'] = $row['data'];
             $processed[$id]['stuff'] = $row['stuff'];
             /* many more similar lines */
        }

        $unique = array();
        $unique['cost'] = $row['cost'];
        /* a few more similar lines */

        $processed[$id]['prices'][$row['date']] = $unique;
    }

任何人都可以确认使用 PHP 的“if”或条件确实比分配更需要计算吗?谢谢。

[我作为编辑的回答]

我对使用 IIS 运行的 FastCGI PHP 进行了一些独立测试(没有真实数据或其他代码开销):

function testif()
{
    $i = 0;
    while ($i < 100000000)
    {
        if (1 != 0)  /* do nothing */;
        $i++;
    }

    return "done";
}

第一次运行: 20.7496500015256748 秒。

第二次运行: 20.8813898563381191 秒。

function testassign()
{
    $i = 0;
    while ($i < 100000000)
    {
        $x = "a 26 character long string";
        $i++;
    }

    return "done";
}

第一次运行: 21.0238358974455215 秒。

第二次运行: 20.7978239059451699 秒。

【问题讨论】:

  • 这在我看来像是过早的优化。与数据库请求和来回流动的数据相比,您的 if 与分配性能将是九牛一毛。优化数据库和网络,不是if语句。
  • 不确定问题的答案是什么(我认为它不会减慢速度),但是您不能轻松地计算代码执行所需的时间,然后尝试更改吗?跨度>
  • @mellamokb:杯水车薪是相当重要的;然而,沧海一粟……
  • @mellamokb,如果可以进行其他优化,现在还为时过早。事实上,这是针对网络传输进行优化的。我实际上并不关心这个实现。我想知道是否有人真的知道可以证实我的发现的 cpu 时间。
  • 过早优化 = 邪恶

标签: php performance conditional variable-assignment


【解决方案1】:

嗯,与将 JSON 数据传输到客户端所需的时间相比,这样的差异确实是沧海一粟。
哎呀,即使是单独的 JSON 编码也会在编码数据时执行数千个这样的 if-s 和分配! 做测试来比较这些事情是你做错了什么。

这是导致此类问题的非常有限的观点
虽然涉及数以万计的其他“CPU 周期”,但千差万别没有任何区别。

  • 有一个网络服务器可以处理您的请求
  • 有一个 php 解释器(默认情况下,它必须解析整个代码,逐个字符地拾取它)
  • 有一个数据库查找,它必须处理千兆字节的数据
  • 存在网络延迟。

因此,为了进行充分的比较,必须将所有这些问题都纳入他们的测试中。并且只有在现实生活中的测试显示出任何差异时才开始担心。否则它将是完整的,完全是浪费时间。

这类问题是我们可怜的 PHP 社区中最邪恶的事情之一。
在性能方面没有什么不好的。 但是没有什么比这种“什么是更快”的问题更糟糕了。

而且“这只是一个理论问题!”不是借口。这些问题从来都不是理论上的,对自己诚实。一个对所有细节真正感兴趣的人,采用另一种方式 - 处理源代码、调试器和分析器,而不是运行愚蠢的“无数次迭代”测试。

真正关心速度的人首先进行测量。这样的测量称为“分析”,其目标是找到一个瓶颈——这确实会使您的应用程序变慢。

但是,有时不需要复杂的测量,只需稍加思考即可。
例如,如果您有太多重复数据 - 害羞地不要求您的数据库先返回较小的数据集?

【讨论】:

  • 我认为你不应该指责说谎。使用 PHP 编码时,为什么要使用 echo 而不是 print?你明白我的意思吗?如果我不编码为 JSON 怎么办?我以前不得不写过其他这样的循环。我想知道这样做的最佳方式。
  • @sims 是的,没有一个理由更喜欢 echo 而不是 print。这就是重点,您似乎无法理解:(唯一的希望是测试我之前在 cmets 中告诉您的方式。您不会有任何不同。试试吧。
  • Echo 肯定比 print 快一点点。仅出于这个原因,除非您确实需要打印,否则为什么不使用 echo 呢?这是我的问题的性质,您似乎没有掌握。在你写之前我明白你的意思。这不是大学,也不是这里的每个人都是 12 岁。所以也许只是回答这个问题,尽量不要讲课。这与优化无关。这是关于编码偏好。如果一个比另一个更快,甚至是一点点,我会这样写。听起来是个好主意,不是吗?
  • @sims:不,因为您在编写代码时不应该考虑这样的事情。 Col Shrapnel 试图表达的观点是,就“最佳实践”而言,过早优化是一种明显的反模式。你不应该“除非你真的需要打印,否则总是使用回声”,因为你必须考虑你是否真的需要打印。只需使用 print,直到您通过仔细的分析证明它在您的代码中太慢。然后,并且只有在那时,您才应该通过用替代结构替换语句来进行优化。
  • @sims 当然没有 :) echo 键入起来更短,这是首选 echo 而不是打印的唯一原因。看。你已经失去了几个小时试图实现“哪个更快”。你永远不会从那个“优化”中得到它。那就是问题所在。另一个问题是你的问题是无止境的。每种语言结构都可以用另一种代替。真的 - 有成千上万这样的潜在比较。您可以花费一生的时间来寻找这种毫秒级的差异。从来没有收获。这就是为什么只有分析才能成为此类问题的原因,原因应该是真实的,而不是虚构的
【解决方案2】:

我相信条件句在任何语言中都比较慢。这与编译器和 CPU 如何与代码交互有关。 CPU 查看编译器生成的操作码并尝试将未来的指令预取到缓存中。如果您正在分支,那么它可能无法缓存下一条指令。我认为有一些规则,最有可能的代码块应该在 if 部分,而这种情况在“else”块中出现的频率较低。

我做了一个快速的谷歌搜索,不久前 StackOverflow 上有另一个相关的问题/答案:Effects of branch prediction on performance?

【讨论】:

  • 感谢您回答问题,而不是试图解释为什么我的问题是邪恶的。
  • 谁对这个答案投了反对票?确实有人有问题。投反对票的人能说出为什么这个答案不正确吗?
【解决方案3】:

正如我已经在第一篇文章的评论中写的那样:

与“性能:if vs 分配”,但一种方法 文本数据要小得多 压缩它(gzip/deflate)。你说 大多数数据是重复的 - 那 意味着它会有很大的 压缩率。压缩可以 在服务器中全局启用 配置,即,您不必 为此更改您的脚本。

压缩的“已处理数据”可能会比“完整数据”小一些,但我怀疑它可能会小 80%。


现在谈谈性能。

代码:

$time = microtime(true);
$data = array();
for ( $n = 0; $n < 25000; ++$n ) {
    $data[] = array('id' => $n, 'text' => 'foo bar', 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3');
    $data[] = array('id' => $n, 'text' => 'foo bar', 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3');
    $data[] = array('id' => $n, 'text' => 'foo bar', 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3');
    $data[] = array('id' => $n, 'text' => 'foo bar', 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3');
    $data[] = array('id' => $n, 'text' => 'foo bar', 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3');
}
printf("%.05f\n\n", microtime(true) - $time);

for ( $n = 0; $n < 10; ++$n ) {
    $time = microtime(true);
    $tmp = array();
    foreach ( $data as $row ) {
        $id = $row['id'];
        $tmp[$id]['text'] = $row['text'];
        $tmp[$id]['key1'] = $row['key1'];
        $tmp[$id]['key2'] = $row['key2'];
        $tmp[$id]['key3'] = $row['key3'];
    }
    printf("%.05f\n", microtime(true) - $time);
}
echo "\n";

for ( $n = 0; $n < 10; ++$n ) {
    $time = microtime(true);
    $tmp = array();
    $id = null;
    foreach ( $data as $row ) {
        if ( $row['id'] !== $id ) {
            $id = $row['id'];
            $tmp[$id]['text'] = $row['text'];
            $tmp[$id]['key1'] = $row['key1'];
            $tmp[$id]['key2'] = $row['key2'];
            $tmp[$id]['key3'] = $row['key3'];
        }
    }
    printf("%.05f\n", microtime(true) - $time);
}
echo "\n";

for ( $n = 0; $n < 10; ++$n ) {
    $time = microtime(true);
    $tmp = array();
    foreach ( $data as $row ) {
        if ( !isset($tmp[$row['id']]) ) {
            $id = $row['id'];
            $tmp[$id]['text'] = $row['text'];
            $tmp[$id]['key1'] = $row['key1'];
            $tmp[$id]['key2'] = $row['key2'];
            $tmp[$id]['key3'] = $row['key3'];
        }
    }
    printf("%.05f\n", microtime(true) - $time);
}
echo "\n";

结果:

0.26685; 0.32710; 0.30996; 0.31132; 0.31148; 0.31072; 0.31036; 0.31082; 0.30957; 0.30952; 
0.21155; 0.21114; 0.21132; 0.21119; 0.21042; 0.21128; 0.21176; 0.21075; 0.21139; 0.21703; 
0.21596; 0.21576; 0.21728; 0.21720; 0.21610; 0.21586; 0.21635; 0.22057; 0.21635; 0.21888; 

我不知道为什么,但第一次测试的第一次计时总是小于同一测试的其他计时(0.26-0.27 vs 0.31-0.32)。除此之外,在我看来,检查行是否已经存在是值得的。

【讨论】:

  • 我没有那样做。显然是一些怪人,因为他/她没有留下任何cmets。它真的要小得多。如果你有一行只有 20% 的字段数据发生变化,它可以变得更小。不,我无法优化该数据。来自第 3 方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-15
  • 1970-01-01
  • 2011-02-15
  • 1970-01-01
相关资源
最近更新 更多