2013-06-24 3 views
2

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

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

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

$a на самом деле очень большой и разреженная матрица (30k * 30k), но я не могу держать его в памяти (8 Гб, кажется, не хватает ОЗУ), поэтому я сохраняю просто «разреженное представление» (в основном каждая строка является строкой) и используйте 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) // e.g. $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 *, но я бы хотел избежать этого, если можно увеличить производительность, чтобы я мог выполнять его в часах (а не в днях).

Спасибо.

+0

возможно попробовать использовать str_getcsv() вместо того, чтобы взорваться() –

+0

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

+1

использовать структуры данных индекса, например, в базе данных или даже лучше: использовать базу данных – hek2mgl

ответ

-1

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

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

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

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

+2

Просто переписывать его на C не гарантирует, что он пойдет быстрее. Проблема, скорее всего, заключается в объеме данных; то есть ввода/вывода и в том, насколько сложна обработка. –

+1

Это выглядит как вычисление матрицы интенсивного процессора. Просто зная, как два языка хранят основные структуры данных, я ожидал бы, по крайней мере, улучшения порядка с помощью C. –

-1

Вы слышали о компиляторе Facebook hiphop. Вы можете попробовать this. Его помощь в том, чтобы выполнить ваш скрипт намного быстрее и принять минимальный регресс.

+1

Да, нет. Замена среды выполнения не приведет к экспоненциальному увеличению производительности. Хип-хоп может быть быстрее, но это не волшебная таблетка. Фактически для большинства случаев использования hiphop будет стоить вам больше средств, чем вы сэкономите из-за дополнительного времени разработчика и sys-admin, которое оно будет потреблять. Facebook написал это, потому что у них есть шкала, чтобы оправдать это. * Огромное * большинство других сайтов не ... – ircmaxell

8

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

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

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

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

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

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

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

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

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

+0

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

+1

@Eugenio: Foreach - это * не * ваше узкое место. Узким местом будет ваш алгоритм. Вот почему я предложил формализовать его, чтобы вы могли настроить его лучше. Или просто перестройте алгоритм для более эффективной работы. – ircmaxell

+3

Кроме того, downvoters, что еще можно сказать, учитывая полное отсутствие информации о том, что пытается сделать OP? У него есть проблема с алгоритмом. Вы не решаете проблему алгоритма, перейдя на C. Вы решаете его путем рефакторинга алгоритма. Несомненно, наступает время, когда портирование на C или другое время выполнения является опцией, но это не первый шаг (так как он не даст вам прироста заказов). Поэтому, если ОП не отправляет фактический алгоритм, этот ответ - лучший способ помочь ему. Это единственный ответ, который может привести к изменениям порядка величины, которые он после. – ircmaxell