Czy istnieje sposób na użycie shell_exec bez czekania na zakończenie polecenia?

95

Mam zadanie wymagające dużej ilości procesów, które chciałbym wykonać w tle.

Użytkownik klika stronę, uruchamia się skrypt PHP, a na końcu, w razie potrzeby, po spełnieniu pewnych warunków, musi uruchomić skrypt powłoki EG:

shell_exec('php measurePerformance.php 47 844 [email protected]');

Obecnie używam shell_exec , ale wymaga to od skryptu czekania na wyjście. Czy jest jakiś sposób na wykonanie polecenia, które chcę, bez czekania na jego zakończenie?

ToughPal
źródło
UWAGA: Proces musi rozpocząć się natychmiast, więc cron nie jest opcją.
ToughPal
2
Krótka uwaga: upewnij się, że strona nie będzie dostępna dla wszystkich (wyszukiwarki / nieuczciwi użytkownicy), a jeśli pracujesz w środowisku współdzielonym, czas wykonania wszystkich twoich skryptów (w szczególności php!) Jest prawdopodobnie ograniczony. W każdym razie możesz rzucić okiem na set_time_limit / php.ini.
merkuro
Możliwy duplikat php wykonuje proces w tle
Sean the Bean

Odpowiedzi:

150

Co powiesz na dodanie.

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

shell_exec('php measurePerformance.php 47 844 [email protected] > /dev/null 2>/dev/null &');

Zauważ, że to również usuwa stdio i stderr.

drganie
źródło
2
Nie. Żadnych skutków ubocznych. Jeśli kiedyś zdecydujesz, że chcesz uzyskać wyjście stdio lub stderr swojego procesu, rozważ stackoverflow.com/questions/45953/ ...
jitter
1
Pytanie: To po prostu odrzucenie wyniku, prawda? Czy PHP nadal czeka na zakończenie procesu przed kontynuowaniem wykonywania, czy też uruchamia się i zapomina?
Alan Storm
5
Tak odrzuca. Tak, odpal i zapomnij
jitter
3
Uwaga: > /dev/null 2>&1 &jak widać w innych odpowiedziach, jest to zwięzła forma > /dev/null 2>/dev/null &podana tutaj. Zasadniczo oznacza to „przekieruj STDERR (2) do tego samego miejsca co STDOUT (& 1)”.
rymo
3
Zwykle otrzymuję PID uruchomionego skryptu, dodając echo $! >> /tmp/pid.txt na końcu polecenia exec, ale przekierowując wyjście i błąd do / dev / null, nie ma już pliku pid: czy ktokolwiek z was może uzyskać PID skryptu uruchomionego przez exec, nie czekając na wyjście?
hugsbrugs
28

Spowoduje to wykonanie polecenia i odłączenie od działającego procesu. Oczywiście może to być dowolne polecenie. Ale do testu możesz utworzyć plik php za pomocą polecenia sleep (20).

exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");
Brent Baisley
źródło
czy lepiej to czy shell_exec?
realtebo
cześć, czy mogę uruchomić funkcję za pomocą tego shell_exec ("nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2> & 1 &");
Waseem Bashir
Dlaczego oba nohup i &?
bugmenot123
11

Możesz również natychmiast przekazać dane wyjściowe klientowi, a następnie kontynuować przetwarzanie kodu PHP.

Jest to metoda, której używam do długo oczekujących wywołań Ajax, które nie miałyby żadnego wpływu po stronie klienta:

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.

Szczegółowe wyjaśnienie można znaleźć tutaj: http://oytun.co/response-now-process-later

Oytun
źródło
1
Ops ... Budziłem tutaj pytanie zombie, nie zdawałem sobie sprawy. Ale ta odrobina informacji może być korzystna dla innych.
Oytun
3
To nie ma nic wspólnego z shell_exec
bugmenot123
8

W systemie Windows 2003, aby wywołać inny skrypt bez czekania, użyłem tego:

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

Działa to tylko PO nadaniu zmiany uprawnień na cmd.exe- dodaj Odczyt i Wykonaj dla IUSR_YOURMACHINE(ustawiłem również zapis na Odmów).

Jason Plank
źródło
7

Jasne, windowsmożesz użyć:

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

Uwaga:

Jeśli pojawi się COMbłąd, dodaj rozszerzenie do swojego php.inii uruchom ponownie apache:

[COM_DOT_NET]
extension=php_com_dotnet.dll
CONvid19
źródło
Nie mam pojęcia, ale zadziałało. Proszę o wyjaśnienie, czym jest wscript.shell i do czego służy.
GeekWithGlasses,
czy możesz wyjaśnić, dlaczego ta linia nie daje żadnych wyników? `$ oExec = $ WshShell-> Uruchom ('C: \ Users \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C: \ xampp \ htdocs \ composer \ test_0.js', 0 , false); `
GeekWithGlasses
Możesz mieć błąd w pliku test_0.js, sprawdź dziennik Phantom.
CONvid19
6

Użyj popenpolecenia PHP , np .:

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

Spowoduje to utworzenie procesu potomnego, a skrypt uruchomi się w tle bez czekania na wyjście.

Jason Plank
źródło
4
Czeka na zakończenie procesu potomnego. Przynajmniej na Win
Max Chernopolsky
Tło jest tutaj osiągane za pomocą polecenia "start" systemu Windows, które poprzedza exe, który chcesz uruchomić, nie zadziała, jeśli go pominiesz, i nie spodziewałbym się, że zadziała na innym systemie operacyjnym ... ale TAK na mnie działa, dzięki! :-)
Antony
1

Jeśli jest poza stroną internetową, zalecam wygenerowanie jakiegoś sygnału (na przykład upuszczenie pliku do katalogu) i zlecenie pracy cron, aby odebrała pracę, którą należy wykonać. W przeciwnym razie prawdopodobnie dostaniemy się na terytorium używania pcntl_fork()i exec()z wnętrza procesu Apache, a to po prostu złe mojo.

chaos
źródło
1
powiedziałeś, że to zły mojo. czy możesz to rozwinąć?
Mayank,
1

To zadziała, ale będziesz musiał uważać, aby nie przeciążać serwera, ponieważ będzie tworzył nowy proces za każdym razem, gdy wywołasz tę funkcję, która będzie działać w tle. Jeśli tylko jedno jednoczesne połączenie w tym samym czasie, to obejście wystarczy.

Jeśli nie, radziłbym uruchomić kolejkę komunikatów, taką jak na przykład beanstalkd / gearman / amazon sqs.

Alfred
źródło