大型PHP 5.4脚本变慢

时间:2015-01-07 10:47:10

标签: php performance

我正在使用php脚本来更新产品数据。 虽然消耗的内存是不变的,但每1000个产品的消耗时间一直在增加:

[26000 - 439.75 MB / 14.822s]..........
[27000 - 439.25 MB / 15.774s]..........
[28000 - 438.25 MB / 15.068s]..........
[29000 - 437.75 MB / 16.317s]..........
[30000 - 437.25 MB / 16.968s]..........
[31000 - 436.25 MB / 17.521s]....

即使我禁用除了读取包含CSV数据的变量行之外的所有内容,效果也是相同的,但增加率较低:

[65000 - 424.75 MB / 0.001s]..........
[66000 - 424.75 MB / 0.63s]..........
[67000 - 424.75 MB / 0.716s]..........
[68000 - 424.75 MB / 0.848s]..........
[69000 - 424.75 MB / 0.943s]..........
[70000 - 424.25 MB / 1.126s]..........
[71000 - 423.5 MB / 1.312s]....

我尝试更改GC设置(php -dzend.enable_gc = 1和php -dzend.enable_gc = 0)。

我提前加载了我的数据:

$this->file = file($file_path);

检索下一行:

$line = array_shift($this->file);

我不知道为什么这会不断增加所需的时间,特别是当我只是对行进行array_shift而不对其执行任何操作时。

我目前的解决方案是将文件拆分为10,000个,这对于包含超过300.000行的文件来说不是理想的解决方案,并且必须每天更新。

至少可以理解这里发生的事情......

提前感谢任何提示。

3 个答案:

答案 0 :(得分:3)

array_shift()

的问题

对于数组中的每个元素,内部维护的部分数据是一个序列号,用于标识该元素在数组中的位置。这些值实际上是顺序整数,从第一个元素的0开始。不要将它与枚举数组的键值混淆,它纯粹在内部进行维护,并且与键完全分离,以便您可以进行关联排序,从而有效地重新组织这些内部位置值。

向数组添加新元素时,需要为其指定新的序列值。如果您只是将新元素添加到数组的末尾,那么它就像获取前一个最高序列值一样简单,添加一个,并将其指定为新元素的序列值。 ..一个简单的O(1)活动。同样,如果删除最后一个元素,则可以简单地将其删除,并且所有其他元素的序列仍然有效。

但是,如果使用array_unshift()将新元素添加到数组的开头,则会为其分配0值,并且数组中已有的每个现有元素都需要将其序列值增加1,所以PHP内部必须遍历每个元素,使其成为O(n)事务。同样,一旦从数组中删除了第一个元素,array_shift()必须为每个剩余的数组元素判断序列值,也就是O(n)。如果您的阵列非常大,这可能是一个主要的开销。

一般表现

为了解决您的性能问题....为什么要一次性将整个文件读入内存?为什么你不能一次只处理一行呢?

$fh = fopen('filename.txt', 'r');
while (!feof($fh)) {
    $item = fread($fh);
    .... processing here
}
fclose($fh);

并且不要试图超越PHP的垃圾收集

答案 1 :(得分:0)

array_shift()在技术上运行得越快,因为它必须重新索引一个较小的集合。

您是否正在使用返回的结果执行其他操作?

或者,您可以考虑在循环之前反转数组:

$reversed = array_reverse($file);

然后弹出循环中的最后一个值

$item = array_pop($reversed);

答案 2 :(得分:0)

是否有特定原因需要使用array_shift()?

也许只是阅读文件并关闭它会使你的脚本运行得更快:

$this->file = file($file_path);
foreach ($this->file as $line) {
  // do the thing you need to do
}
unset ($this->file);

另一件事是你似乎正在阅读一个数组($file)并将其转换为另一个数组($line)。也许值得使用$file数组?

我不确定你到底在做什么 - 但希望这些建议可能有所帮助。