在foreach循环参数中爆炸数组

时间:2011-05-02 19:55:00

标签: php performance foreach

foreach(explode(',' $foo) as $bar) { ... }

VS

$test = explode(',' $foo);
foreach($test as $bar) { ... }

在第一个示例中,每次迭代是explode $foo字符串还是PHP将其保存在内存中,并在其自己的临时变量中爆炸?从效率的角度来看,创建额外变量$test或两者都非常相等是否有意义?

4 个答案:

答案 0 :(得分:22)

我可以做出有根据的猜测,但让我们尝试一下

我认为有三种主要方法可以解决这个问题。

  1. 在进入循环之前爆炸并分配
  2. 在循环内爆炸,没有作业
  3. string tokenize
  4. 我的假设:

    1. 可能因分配
    2. 而消耗更多内存
    3. 可能与#1或#3相同,不确定哪个
    4. 可能更快,更小的内存占用
    5. 方法

      这是我的测试脚本:

      <?php
      
      ini_set('memory_limit', '1024M');
      
      $listStr = 'text';
      $listStr .= str_repeat(',text', 9999999);
      
      $timeStart = microtime(true);
      
      /*****
       * {INSERT LOOP HERE}
       */
      
      $timeEnd = microtime(true);
      $timeElapsed = $timeEnd - $timeStart;
      
      printf("Memory used: %s kB\n", memory_get_peak_usage()/1024);
      printf("Total time: %s s\n", $timeElapsed);
      

      以下是三个版本:

      1)

      // explode separately 
      $arr = explode(',', $listStr);
      foreach ($arr as $val) {}
      

      2)

      // explode inline-ly 
      foreach (explode(',', $listStr) as $val) {}
      

      3)

      // tokenize
      $tok = strtok($listStr, ',');
      while ($tok = strtok(',')) {}
      

      结果

      explode() benchmark results

      结论

      看起来有些假设被证明是错误的。你不爱科学吗? : - )

      • 总体而言,这些方法中的任何一种方法都足够快,可以列出“合理大小”(几百或几千)。
      • 如果您正在迭代 huge ,时差相对较小,但内存使用量可能会有一个数量级的差异!
      • 当你explode()内联而没有预先分配时,由于某种原因它会慢一点。
      • 令人惊讶的是,标记化比显式迭代声明的数组慢了 。在这么小的范围内工作,我认为这是由于每次迭代都要调用strtok()的调用堆栈开销。更多内容如下。

      就函数调用的数量而言,explode()确实是顶级标记化。 O(1) vs O(n)

      我在图表中添加了奖励,我在循环中使用函数调用运行方法1)。我使用strlen($val),认为这是一个相对类似的执行时间。这是有争议的,但我只是想提出一个普遍的观点。 (我只运行了strlen($val)并忽略了它的输出。我做了将它分配给任何东西,因为分配将是额外的时间成本。)

      // explode separately 
      $arr = explode(',', $listStr);
      foreach ($arr as $val) {strlen($val);}
      

      从结果表中可以看出,它成为三者中最慢的方法。

      最后的想法

      这很有趣,但我的建议是做任何你认为最易读/可维护的事情。只有当你真正处理一个非常大的数据集时,你才会担心这些微观优化。

答案 1 :(得分:6)

在第一种情况下,PHP会将其爆炸一次并将其保留在内存中。

创建不同变量或其他方式的影响可以忽略不计。无论用户是否定义,PHP解释器都需要维护指向下一个项目位置的指针。

答案 2 :(得分:3)

从内存的角度来看,它没有什么区别,因为PHP使用copy on write concept

除此之外,我个人会选择第一个选项 - 它是一条线,但不是那么可读(imho!)。

答案 3 :(得分:1)

效率在什么意义上?内存管理还是处理器?对于内存而言,处理器不会产生任何影响 - 您始终可以执行$foo = explode(',', $foo)