Большой скрипт PHP 5.4 становится медленнее

0

Я использую php-скрипт для обновления данных продукта. Хотя потребляемая память постоянна, потребляемое время на 1.000 продуктов постоянно увеличивается:

[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 строк и должен обновляться каждый день.

Было бы неплохо хотя бы понять, что здесь происходит...

Заранее благодарим за любые подсказки.

  • 2
    Используйте настоящий профилировщик и узнайте.
Теги:
performance

3 ответа

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

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 как есть?

Я не уверен, что вы делаете, но, надеюсь, эти предложения могут помочь.

0

array_shift() должен технически работать быстрее, чем больше он используется, так как он должен повторно индексировать меньший набор.

Вы делаете что-нибудь еще с возвращенным результатом?

Альтернативно, вы можете подумать об обращении массива до цикла:

$reversed = array_reverse($file);

А затем вытащить последнее значение внутри вашей циклы

$item = array_pop($reversed);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню