Есть ли способ использовать shell_exec, не дожидаясь завершения команды?

95

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

Пользователь щелкает страницу, запускается сценарий PHP, и, наконец, в зависимости от некоторых условий, если требуется, он должен запустить сценарий оболочки EG:

shell_exec('php measurePerformance.php 47 844 email@yahoo.com');

В настоящее время я использую shell_exec , но для этого необходимо, чтобы сценарий ждал вывода. Есть ли способ выполнить нужную мне команду, не дожидаясь ее завершения?

ToughPal
источник
ПРИМЕЧАНИЕ. Процесс должен запускаться немедленно, поэтому cron не подходит.
ToughPal
2
Небольшое примечание: убедитесь, что страница не будет доступна всем (поисковым системам / мошенникам), и если вы находитесь в общей среде, время выполнения всех ваших скриптов (в частности, php!), Вероятно, ограничено. В любом случае вы можете взглянуть на set_time_limit / php.ini.
merkuro
Возможный дубликат php выполняет фоновый процесс
Шон Бин

Ответы:

150

Как насчет добавления.

"> /dev/null 2>/dev/null &"

shell_exec('php measurePerformance.php 47 844 email@yahoo.com > /dev/null 2>/dev/null &');

Обратите внимание, что это также избавляет от stdio и stderr.

дрожь
источник
2
Нет. Никаких побочных эффектов. Если вы когда-нибудь решите, что хотите, чтобы ваш процесс выводил stdio или stderr, подумайте о stackoverflow.com/questions/45953/…
jitter
1
Вопрос: Это просто отбрасывание вывода, верно? PHP все еще ждет завершения процесса, прежде чем продолжить выполнение, или он запускается и забывает?
Алан Сторм,
5
Да отбрасывает. Да, стреляй и забудь
jitter
3
Примечание: > /dev/null 2>&1 &как видно из других ответов, > /dev/null 2>/dev/null &здесь дана краткая форма . По сути, это означает «перенаправить STDERR (2) в то же место, что и STDOUT (& 1)».
rymo
3
Я обычно получаю PID запущенного скрипта, добавляя echo $! >> /tmp/pid.txt в конце команды exec, но перенаправив вывод и ошибку в / dev / null, больше никакого файла pid: может ли кто-нибудь из вас получить PID сценария, запущенного exec, не дожидаясь вывода?
hugsbrugs
28

Это выполнит команду и отключится от запущенного процесса. Конечно, это может быть любая команда. Но для теста вы можете создать файл php с помощью команды sleep (20) it.

exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");
Брент Бэйсли
источник
что лучше это или shell_exec?
realtebo
привет, могу ли я запустить функцию, используя этот shell_exec ("nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2> & 1 &");
Васим Башир
Почему и то nohup и другое& ?
bugmenot123
11

Вы также можете немедленно вернуть результат клиенту и продолжить обработку кода PHP после этого.

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

ob_end_clean();
ignore_user_abort();
ob_start();
header("Connection: close");
echo json_encode($out);
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();
// execute your command here. client will not wait for response, it already has one above.

Вы можете найти подробное объяснение здесь: http://oytun.co/response-now-process-later

Ойтун
источник
1
Опс ... Я не понял, что тут зомби-вопрос. Но эта информация может быть полезна другим.
Ойтун
3
Это не имеет ничего общего с shell_exec
bugmenot123
8

В Windows 2003, чтобы вызвать другой сценарий без ожидания, я использовал это:

$commandString = "start /b c:\\php\\php.EXE C:\\Inetpub\\wwwroot\\mysite.com\\phpforktest.php --passmsg=$testmsg"; 
pclose(popen($commandString, 'r'));

Это работает только ПОСЛЕ предоставления разрешения на изменение cmd.exe- добавьте Read и Execute для IUSR_YOURMACHINE(я также установил запись на Deny).

Джейсон Планк
источник
7

Конечно, windowsвы можете использовать:

$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("C:/path/to/php-win.exe -f C:/path/to/script.php", 0, false);

Примечание:

Если вы получили сообщение COMоб ошибке, добавьте расширение в свой php.iniи перезапустите apache:

[COM_DOT_NET]
extension=php_com_dotnet.dll
CONvid19
источник
Понятия не имею, но у меня это сработало. Пожалуйста, объясните, что такое wscript.shell и что он делает.
GeekWithGlasses
не могли бы вы объяснить, почему эта строка не дает никаких результатов? `$ oExec = $ WshShell-> Запустить ('C: \ Users \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C: \ xampp \ htdocs \ composer \ test_0.js', 0 , false); `
GeekWithGlasses
У вас может быть ошибка на test_0.js, проверьте фантомный журнал.
CONvid19
6

Используйте popenкоманду PHP , например:

pclose(popen("start c:\wamp\bin\php.exe c:\wamp\www\script.php","r"));

Это создаст дочерний процесс, и скрипт будет запускаться в фоновом режиме, не дожидаясь вывода.

Джейсон Планк
источник
4
Он ожидает завершения дочернего процесса. Хотя бы на Win
Макс Чернопольский
Фон здесь достигается с помощью команды Windows "start", которая ставит префикс исполняемого файла, который вы хотите запустить, он не будет работать, если вы его пропустите, и я бы не ожидал, что он будет работать на другой ОС ... но он ДЕЙСТВУЕТ у меня работает, спасибо! :-)
Энтони
1

Если он находится за пределами веб-страницы, я рекомендую создать какой-либо сигнал (возможно, сбросить файл в каталог) и попросить задание cron подобрать работу, которую необходимо выполнить. В противном случае мы, скорее всего, попадем на территорию использования pcntl_fork()и exec()изнутри процесса Apache, и это просто плохой моджо.

хаос
источник
1
Вы сказали, что это плохое моджо. не могли бы вы уточнить?
Mayank
1

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

Если нет, то я бы посоветовал запустить очередь сообщений, например, beanstalkd / gearman / amazon sqs.

Альфред
источник