"Forking" a Process and Sending it to Background – in PHP
Hello, PHP programmers!
It is often necessary to launch a process in a separate thread in order to prevent a script from being hanged or stuck at some point.
"Slow" operations, such as big selects from databases, connections to remote servers, work with FTP servers, long loops etc. should be passed to separate processes and let the parent process execute further functions.
With Perl – for instance - it is easy to do that by calling a fork() function. What about PHP which becomes more popular and widespread than Perl and CGI scripts?
According to PHP manual Process Control support in PHP implements the Unix style of process creation, program execution, signal handling and process termination. Process Control functions become available after installation of special library (PCNTL). Process Control support in PHP is not enabled by default. You have to compile the CGI or CLI version of PHP with --enable-pcntl configuration option when compiling PHP to enable Process Control support.
That means if PHP on your server is not configured with the above option, you will not have the opportunity to use any of those functions. What do you have to do if you still need to have that ability?
The simplest way is to use exec function, which is enabled by default and let you execute an external program. You may call this command from inside your PHP script as many times as you need without interrupting the execution of the script.
The only problem is that exec always waits for the command it launched to finish, unless you redirect the output of the child process to the source different than stdout. So if you just execute the following code:
<? exec("/usr/bin/php ./child_script.php"); ?> | your parent script will be waiting for the child_script.php to finish its stuff. Moreover, if you send the process to background:
<? exec("/usr/bin/php ./child_script.php &"); ?> |
you are risking to hang your parent script until the execution of child_script.php ends.
To avoid this redirect the output of child_script.php to /dev/null or some text file, and thus release stdin and stdout streams:
<? exec("/usr/bin/php ./child_script.php > /dev/null 2>&1 &"); ?> |
Please bare in mind that the scripts which you are trying to execute should be allowed to be executed (modify the attributes of the file with chmod ), and the path to php may be different (for instance /usr/local/bin/php).
Voila, you have found the way to "fork" child processes without any obstacles to the parent process.
So how do you check if child_process.php is executed independently? I propose to add the following little test: main.php:
<? exec("/usr/bin/php ./child_script.php > /dev/null 2>&1 &"); if ($fp = fopen("log.txt", "a")) { frwite($fp, "Main process finished at ".date("H:i:s", time())."!\n"); fclose($fp); } ?> |
child_script.php:
<? sleep(10); if ($fp = fopen("log.txt", "a")) { frwite($fp, Child process finished at ".date("H:i:s", time())."!\n"; fclose($fp); } ?> | If everything’s correct, then child_script.php will have finished in about 10 sec after the parent process. So you will see in the log file log.txt the following strings (timestamp will be different of course):
Main process finished at 10:12:05! Child process finished at 10:12:15! |
The above considerations and examples are only applicable to Unix-type systems and do not work under Windows!
Happy programming!
|