Чи є спосіб використовувати shell_exec, не чекаючи завершення команди?


95

У мене є інтенсивне завдання, яке я хотів би виконати у фоновому режимі.

Користувач натискає сторінку, запускається скрипт PHP, і, нарешті, на основі деяких умов, якщо потрібно, він повинен запустити сценарій оболонки, наприклад:

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

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


ПРИМІТКА: Процес повинен розпочатися негайно, тому cron не є варіантом.
— ToughPal

2
Лише коротка примітка: переконайтесь, що сторінка буде доступна не всім (пошукові системи / шахрайські користувачі), і якщо ви перебуваєте у спільному середовищі, час виконання всіх ваших скриптів (зокрема php!), Ймовірно, обмежений. У будь-якому випадку ви можете поглянути на set_time_limit / php.ini.
— merkuro

Відповіді:


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/…
— джиттер

1
Питання: Це просто відкидання результату, так? PHP все ще чекає завершення процесу, перш ніж продовжувати виконання, або він запускається і забуває?
— Алан Сторм

5
Так викидає. Так вогонь і забудь
— тремтіння

3
Примітка: > /dev/null 2>&1 &як видно з інших відповідей, це стисла форма, > /dev/null 2>/dev/null &наведена тут. В основному це означає "перенаправити STDERR (2) туди ж, де STDOUT (& 1)".
— римо

3
Зазвичай я отримую PID запущеного сценарію, додаючи echo $! >> /tmp/pid.txt в кінці команди exec, але, перенаправивши вивід і помилку на / dev / null, більше не буде pid-файлу: чи може хтось із вас отримати PID сценарію, запущеного exec, не чекаючи вихідних даних?
— hugsbrugs

28

Це виконає команду та від’єднається від запущеного процесу. Звичайно, це може бути будь-яка ваша команда. Але для тесту ви можете створити php-файл із командою sleep (20).

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 &");
— Waseem Bashir

Чому і те, 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- додайте Читати та Виконувати для IUSR_YOURMACHINE(я також встановив запис на Заборонити).


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

Я не маю ідеї, але це спрацювало для мене. Будь ласка, поясніть, що таке 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
Це чекає, поки закінчиться процес дитини. Принаймні на Перемогу
— Макс Чернопольський

Передустановка тут досягається за допомогою команди Windows "start", яка додає префікс до exe, який ви хочете запустити, він не буде працювати, якщо його опустити, і я б не очікував, що він буде працювати в іншій ОС ... але це РОБИТЬ працює для мене, дякую! :-)
— Антоній

1

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


1
ти сказав, що це поганий моджо. Ви можете, будь ласка, детальніше розказати?
— Mayank

1

Це буде працювати, але вам доведеться бути обережним, щоб не перевантажити ваш сервер, оскільки він створюватиме новий процес кожного разу, коли ви викликаєте цю функцію, яка буде працювати у фоновому режимі. Якщо одночасно здійснюється лише один одночасний дзвінок, тоді цей обхідний спосіб зробить свою роботу.

Якщо ні, то я порадив би запустити чергу повідомлень, наприклад, beanstalkd / gearman / amazon sqs.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.