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@yahoo.com');

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?


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

Odpowiedzi:


150

Co powiesz na dodanie.

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

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

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


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

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


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).


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

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.


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.


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.