увеличить производительность PHP-скриптов с интенсивным использованием процессора

У меня есть PHP-скрипт, для выполнения которого требуется несколько часов (возможно, дней). Это довольно просто, но очень интенсивно для процессора, большая часть времени выполнения расходуется (я могу сказать, выполнив этот скрипт):

  1. $array = explode(',', $a[$i]); где $a[$i] – очень длинная строка, представляющая вектор из 30k элементов, разделенных запятой

  2. foreach($array as $key => $value) ; где для каждого цикла выполняются некоторые операции in_array () и сравнения и назначения

$a на самом деле очень большая и разреженная матрица (30k * 30k), но я не могу сохранить ее в памяти (8GB, кажется, недостаточно RAM), поэтому я сохраняю просто «разреженное представление» (в основном каждая строка является строкой) и использовать explode() любое время, когда мне нужно работать в строке.

Я знаю, что переписывание всего на C (или других языках) улучшит производительность (сколько?), Но прежде чем делать это, я хотел бы знать, могу ли я сделать что-либо, чтобы улучшить время выполнения на PHP.

EDIT после ответов.

Я попробовал несколько ваших советов, и вот мой отчет:

1) str_getcsv в большинстве случаев медленнее, чем взрывается

2) SPLFixedArray уменьшает память, запрошенную для хранения матрицы, но все же 8GB недостаточно для матрицы 30k x 30k, поэтому я не думаю, что это может помочь; реальной проблемой здесь является отсутствие разреженного представления для матрицы в PHP. Я думаю

3) Я не могу сохранить все результаты операций взрыва, потому что, тем не менее, это означало бы сохранение всей матрицы в памяти (не хватает ОЗУ)

4) Я пробовал подход к базе данных, даже если бы был уверен, что это было бы медленнее: я сохранил тройки (i, j, value) для представления каждого матричного элемента; даже удаляя менее важные значения (я могу пожертвовать значениями меньше порога и получить менее точный результат, но все же полезный) и хранения всего 18 миллионов кортежей, подход с mysql myisam намного медленнее, чем мой массив в памяти.

5) Я пробовал подход к базе данных с помощью механизма MEMORY (таблица mysql в ОЗУ) и хранения всех матричных элементов, кроме тех, которые имеют нулевое значение; имея на данный момент 42 миллиона записей … это быстрее, а не на порядок, но в 2-4 раза быстрее … Думаю, я смогу закончить работу за 5 дней вместо 15-20 … это все равно слишком много (Я хотел бы закончить через 24 часа), если у вас есть другие предложения, которые вам очень нравятся

EDIT 2: я объясняю проблему

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

У меня есть матрица, представляющая расстояния между узлами; расстояние в целое число и также может быть бесконечным.

У меня есть таблица памяти, представляющая каждое расстояние с тройками: node_1, node_2, distance (отображаются только бесконечные расстояния).

У меня есть такой жадный алгоритм, который я не писал, и я должен оптимизировать его выполнение в допустимое время (допустим, менее одного дня) на ноутбуке с 8 ГБ оперативной памяти.

Алго в основном получает входные данные двух узлов и проектирует путь между начальным узлом и конечным узлом шаг за шагом в соответствии со следующими двумя свойствами, которые должны быть проверены на каждом шаге:

  • новый промежуточный узел должен быть выбран из набора узлов, которые ближе к конечному узлу относительно текущего узла
  • среди этих узлов выбран тот, который ближе к текущему узлу

Пожалуйста, учтите, что 1) неравенство треугольника НЕ ​​выполнено. 2) Это НЕ кратчайшая проблема

Вот несколько псевдокодов для функции, которую я вызываю несколько раз, пока я не буду достаточно близко к конечному узлу:

 get_next_node($node_1, $node_2){ $dist = select distance from distances_table where node_2 = $node_2 and node_1 = $node_1 $candidates_ar = select node_1 from distances_table where node_2 = $node_2 and distance < $dist $distances_ar = select distance from distances_table where node_1 = $node_1 and node_2 in ($candidates_ar) // eg $distances_ar[12] contains distance between node 12 and $node_1 $min = 1000; foreach ($candidates_ar as $value){ if ($distances_ar[$value] < $min){ $min = $distances_ar[$value] $next_node = $value } } } 

Я пропустил много проверок и дополнительной сложности, но это основное, и именно здесь алго проводит большую часть времени.

Я предполагаю, что это можно решить с помощью реализации A *, но я бы хотел его избежать, если можно увеличить производительность, чтобы я мог выполнять ее в часах (а не в днях).

Благодарю.

Solutions Collecting From Web of "увеличить производительность PHP-скриптов с интенсивным использованием процессора"

Хорошо, у вас проблемы с производительностью. Теперь начинается интересная часть.

Первый шаг – это не догадаться . Не начинайте переписывать в C. Не переключайте компиляторы PHP. Это для присосок. Вместо этого начните с попытки найти фактические узкие места.

Получите XDEBUG и создайте профилирование приложения cachegrind . Это покажет вам, где проводится большая часть времени.

Вы также можете использовать xhprof .

Дело в том, что не догадывайтесь, но профиль. Найдите медленные части алгоритмов, а затем выполните их оптимизацию.

Проблема, скорее всего, не в коде, а в алгоритме, который вы используете. Я бы предложил попытаться формализовать алгоритм, чтобы затем вы могли оптимизировать и настраивать детали для своих конкретных ограничений.

Например. Прямо сейчас вы разбираете большие строки CSV. Зачем? Почему бы не вставить это в базу данных и позволить базе данных делать тяжелую работу для вас? Очевидно, это может быть невозможно в вашем конкретном случае использования, но всякий раз, когда я вижу людей, работающих с массивами из 30 тыс. Элементов в PHP, обычно это потому, что они делают что-то, чего они не должны быть в первую очередь.

И если все остальное не работает, попробуйте выполнить алгоритм, чтобы вы могли запускать его по частям. Таким образом, вы можете попытаться сделать снимок карты или подобную технику для настройки времени выполнения.

Короче говоря, это действительно зависит от того, что именно вы делаете. Но повторное кодирование или переключение времени выполнения было бы моим последним средством, а не первым шагом …

Перезаписать его на C было бы намного быстрее!

Вы можете использовать str_getcsv($a[$i]); вместо этого это будет немного быстрее.

Что касается ОЗУ, сделайте то, что вы хотите, с данными, и используйте unset($a[$i]) мере продвижения.

Поэтому либо перепишите на C, либо вы можете сделать это поэтапно, разделите CSV на 10 кусков и обработайте его таким образом, вы можете даже запустить все 10 одновременно, что может увеличить скорость. Или у вас есть файл CSV в базе данных, чтобы действительно сократить скорость.

Вы слышали о компиляторе Facebook hiphop. Вы можете попробовать это . Это помогает выполнять скрипт намного быстрее и требует минимального использования процессора.