在foreach循环参数中爆炸数组

Nig*_*awk 10 php performance foreach

foreach(explode(',' $foo) as $bar) { ... }
Run Code Online (Sandbox Code Playgroud)

VS

$test = explode(',' $foo);
foreach($test as $bar) { ... }
Run Code Online (Sandbox Code Playgroud)

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

Wis*_*guy 22

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

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

  1. 在进入循环之前爆炸并分配
  2. 在循环中爆炸,没有任务
  3. 字符串标记化

我的假设:

  1. 由于赋值,可能会消耗更多内存
  2. 可能与#1或#3相同,不确定是哪一个
  3. 可能更快,更小的内存占用

途径

这是我的测试脚本:

<?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);
Run Code Online (Sandbox Code Playgroud)

以下是三个版本:

1)

// explode separately 
$arr = explode(',', $listStr);
foreach ($arr as $val) {}
Run Code Online (Sandbox Code Playgroud)

2)

// explode inline-ly 
foreach (explode(',', $listStr) as $val) {}
Run Code Online (Sandbox Code Playgroud)

3)

// tokenize
$tok = strtok($listStr, ',');
while ($tok = strtok(',')) {}
Run Code Online (Sandbox Code Playgroud)

结果

explode()基准测试结果

结论

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

  • 从大图来看,任何这些方法对于"合理大小"(几百或几千)的列表来说足够快.
  • 如果你正在迭代巨大的东西,时差相对较小,但内存使用量可能会有一个数量级的差异!
  • 当你explode()没有预先分配内联时,由于某种原因,它会慢一点.
  • 令人惊讶的是,令牌化比显式迭代声明的数组一点.在如此小的范围内工作,我认为这是由于调用堆栈开销对strtok()每次迭代进行函数调用.更多关于此的信息.

就函数调用的数量而言,explode()真正的顶级令牌化.O(1) vs O(n)

我在图表中添加了一个奖励,我在循环中使用函数调用运行方法1).我用过strlen($val),认为这将是一个相对类似的执行时间.这是有争议的,但我只是想提出一个普遍的观点.(我只跑了strlen($val),而忽视它的输出.我并没有把它分配给什么,对于一个任务将是一个额外的时间成本.)

// explode separately 
$arr = explode(',', $listStr);
foreach ($arr as $val) {strlen($val);}
Run Code Online (Sandbox Code Playgroud)

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

最后的想法

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


Sha*_*fiz 6

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

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