性能比较:在foreach()签名中调用explode()与将爆炸数据作为变量传递给foreach()

问题描述 投票:0回答:4
foreach(explode(',' $foo) as $bar) { ... }

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

在第一个示例中,它是每次迭代的

explode
字符串还是 PHP 将其保存在内存中并在其自己的临时变量中分解?从效率的角度来看,创建额外的变量
$foo
有意义还是两者几乎相等?
    

php performance memory foreach explode
4个回答
26
投票
让我们尝试一下

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

进入循环之前爆炸并赋值
  1. 循环内爆炸,无赋值
  2. 字符串标记化
  3. 我的假设:

可能由于分配而消耗更多内存
  1. 可能与#1或#3相同,不确定是哪一个
  2. 可能更快且内存占用更小
  3. 方法

这是我的测试脚本:

$test

这是三个版本:

1)

<?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);

2)

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

3)

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

结果

explode() benchmark results结论

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

从整体上看,这些方法对于“合理大小”(几百或几千)的列表来说都足够快。
  • 如果您要迭代一些
  • 巨大的
  • ,时间差异相对较小,但内存使用量可能会存在一个数量级的差异! 当您在没有预先分配的情况下
  • // tokenize $tok = strtok($listStr, ','); while ($tok = strtok(',')) {}
  • 内联时,由于某种原因它会慢一些。
    令人惊讶的是,标记化比显式迭代声明的数组有点
  • 。在如此小的规模上工作,我相信这是由于每次迭代对 explode() 进行函数调用的调用堆栈开销造成的。下面详细介绍这一点。
    
    
    
  • 就函数调用次数而言,
strtok()

ing 确实领先于标记化。

O(1)
O(n) 我在图表中添加了一个奖励,我在循环中运行方法 1) 并调用函数。我使用了

explode()

,认为这将是一个相对相似的执行时间。这是有争议的,但我只是想表达一个一般性的观点。 (我只运行了

strlen($val)
并忽略了它的输出。我
没有
将它分配给任何东西,因为分配会增加额外的时间成本。) strlen($val)

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

最后的想法

知道这一点很有趣,但我的建议是做任何你认为最具可读性/可维护性的事情。只有当您确实处理非常大的数据集时,您才应该担心这些微观优化。


6
投票

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


3
投票
copy on write 概念

除此之外,我个人会选择第一个选项 - 它少了一行,但可读性并不差(恕我直言!)。


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

    

© www.soinside.com 2019 - 2024. All rights reserved.