Следующий код PHP возвращает мне время выполнения около 3,5 секунд (измеряется несколько раз и усредняется):
$starttime = microtime(true); exec('/usr/local/bin/convert 1.pdf -density 200 -quality 85% 1.jpg'); $endtime = microtime(true); $time_taken = $endtime-$starttime;
Когда я запускаю ту же команду через терминал ssh, время выполнения сокращается примерно до 0,6 секунды (измеряется с помощью time
инструмента командной строки).
Версия библиотеки imagemagick – это
Version: ImageMagick 6.7.0-10 2012-12-18 Q16 http://www.imagemagick.org Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC Features: OpenMP
Что может быть причиной этой разницы во времени?
Один из ответов на аналогичный вопрос здесь о stackoverflow заключался в том, что накладные расходы возникают из-за того, что веб-сервер должен запустить thread / shell. Неужели это действительно причина? Я думал, что потоки являются легкими и не занимают много времени, чтобы начать / прекратить работу.
Перед вызовом exec
i задает количество потоков, используемых imagemagick (поскольку это было / является ошибкой в OpenMP ?, Reference ) до 1 с exec('env MAGICK_THREAD_LIMIT=1');
, Время выполнения от PHP мало меняет, независимо от того, какое значение я установил для MAGICK_THREAD_LIMIT
. Во всяком случае, в этой версии, похоже, не ошибка в OpenMP, так как время выполнения командной строки в порядке.
Любые предложения о том, как я мог бы улучшить время выполнения вышеприведенной команды, будут очень благодарны.
Большое спасибо за Вашу помощь.
Когда вы входите в систему Unix, либо на клавиатуре, либо через ssh, вы создаете новый экземпляр оболочки. Оболочка обычно имеет что-то вроде /bin/sh
или /bin/bash
. Оболочка позволяет выполнять команды.
Когда вы используете exec()
, он также создает новый экземпляр оболочки. Этот экземпляр выполняет команды, которые вы ему отправили, а затем завершает работу.
Когда вы создаете новый экземпляр команды оболочки, у нее есть собственные переменные среды. Поэтому, если вы это сделаете:
exec('env MAGICK_THREAD_LIMIT=1'); exec('/usr/local/bin/convert 1.pdf -density 200 -quality 85% 1.jpg');
Затем вы создаете две оболочки, а параметр в первой оболочке никогда не попадает во вторую оболочку. Чтобы включить переменную окружения во вторую оболочку, вам нужно что-то вроде этого:
exec('env MAGICK_THREAD_LIMIT=1; /usr/local/bin/convert 1.pdf -density 200 -quality 85% 1.jpg');
Теперь, если вы считаете, что сама оболочка может быть проблемой, потому что для создания оболочки требуется слишком много времени, протестируйте ее с помощью чего-то, что вам известно, почти нет времени:
$starttime = microtime(true); exec('echo hi'); $endtime = microtime(true); $time_taken = $endtime-$starttime;
В этот момент вы знаете, чтобы попытаться найти способ ускорить создание оболочки.
Надеюсь это поможет!
Я программировал компьютеры более 56 лет, но это первый раз, когда я столкнулся с такой ошибкой. Таким образом, я потратил почти неделю, пытаясь понять 7X худшую скорость выполнения при выполнении Perl-программы с php через exec и выполнение программы perl непосредственно в командной строке. В рамках этих усилий я также все время рассматривал эту проблему в Интернете. Вот что я нашел: (1) Это ошибка, которая была впервые опубликована в 2002 году и не была исправлена в последующие 11 лет. (2) Ошибка связана с тем, как apache взаимодействует с php, поэтому обе эти организации передают доллар другим. (3) Ошибка одинакова для exec, system или любой из альтернатив. (4) Ошибка не зависит от того, является ли исполняемая программа perl, exe или что-то еще. (5) Ошибка в UNIX и Windows одинакова. (6) Ошибка не имеет ничего общего с imagemagick или с изображениями вообще. Я столкнулся с ошибкой в совершенно другой обстановке. (7) Ошибка не имеет ничего общего с временем запуска для fork, shell, bash, что угодно. (8) Ошибка не исправлена путем изменения владельца службы apache. (9) Я не уверен, но я думаю, что это связано с огромным увеличением накладных расходов при вызове подпрограмм. Когда я столкнулся с этой проблемой, у меня была программа perl, которая выполнялась бы через 40 секунд, но через exec потребовалось 304 секунды. Моим окончательным решением было выяснить, как оптимизировать мою программу, чтобы она выполнялась через 0,5 секунды напрямую или через 3,5 секунды через exec. Поэтому я никогда не решал проблему.
При вызове exec
php не создается поток, он создает новый дочерний процесс. Создание нового процесса – большие накладные расходы.
Однако, когда вы подключаетесь к ssh, вы просто передаете команду для выполнения. Вы не являетесь владельцем этой программы, поэтому она выполняется как пользователь, с которым вы связаны. Для exec
это пользователь, который запускает PHP.
@Philipp, так как у вас есть SSH, и поскольку ваш сервер разрешает доступ к exec()
я предполагаю, что у вас также есть полный корневой доступ к машине.
Доступ root к машине означает, что вы можете изменить настройки ограничения памяти /etc/php5/php.ini
.
Даже без прямого доступа к /etc/php5/php.ini
вы можете проверить, поддерживает ли ваш сервер переопределение директив php.ini
, создав новый файл php.ini
каталоге ваших проектов.
Даже если переопределения не разрешены, вы можете изменить свои настройки памяти из .htaccess
если AllowOverride
– это All
.
Еще одним способом изменения предела памяти является установка его во время выполнения PHP с использованием ini_set('memory_limit', 256);
,
Единственное, что можно сказать о запуске преобразования через exec()
это если вы не планируете получить результат от exec()
и разрешаете ему работать асинхронно:
exec('convert --your-convert-options > /dev/null 2>/dev/null &');
Вышеупомянутый подход обычно полезен, если вы пытаетесь обработать много файлов, вы не хотите дождаться завершения их обработки и не нуждаетесь в подтверждении относительно каждого обрабатываемого.
Используя вышеприведенный код, чтобы выполнить async
запуск exec
для обработки одного файла, потребуется больше времени процессора и больше памяти, чем использование GD / Imagick в PHP. Время / память будет использоваться другим процессом, который не влияет на процесс PHP (заставляя посетителей чувствовать, что сайт движется быстрее), но потребление памяти существует, и когда дело доходит до обработки многих подключений, которые будут учитываться.