An example to explain the use _php of the related functions of multi-process programming in PHP

Source: Internet
Author: User

    PHP has a set of process control functions (which require –enable-pcntl and POSIX extensions at compile time) to enable PHP to implement the same creation process as C, execute programs using the EXEC function, and process signals.
   

<?php header (' Content-type:text/html;charset=utf-8 '); 
  Extension if (!function_exists ("Pcntl_fork")) {die ("Pcntl extention is must!") must be loaded; 
  }///The number of total processes $totals = 3; 
  Number of scripts executed $CMDARR = array (); Array of executed scripts for ($i = 0; $i < $totals; $i + +) {$CMDARR [] = Array ("path" => __dir__. 
  "/run.php", ' pid ' => $i, ' total ' => $totals); }/* Expand: $CMDARR Array ([0] => Array ([path] =>/var/www/html/company/pcntl/ru n.php [PID] => 0 [total] => 3] [1] => Array ([path] =>/va 
      r/www/html/company/pcntl/run.php [PID] => 1 [total] => 3) [2] => Array 
   
  ([path] =>/var/www/html/company/pcntl/run.php [PID] => 2 [total] => 3) ) */pcntl_signal (SIGCHLD, sig_ign); 
  If the parent process does not care about when the subprocess ends, the kernel reclaims after the child process finishes. foreach ($cmdArr as $cmd) {$pid =Pcntl_fork (); 
      Create subprocess//parent processes and child processes execute the following code if ($pid = = 1) {//Error handling: Returns-1 if a child process fails to be created. 
    Die (' could not fork '); 
      The else if ($pid) {//parent process will get the subprocess number, so this is the logic that the parent process executes///If you do not need to block the process and want the child process to exit, you can comment out the pcntl_wait ($status) statement, or write: Pcntl_wait ($status, Wnohang); 
    Wait for child process interrupts to prevent child processes from becoming zombie processes. 
      The else {//subprocess gets a $pid of 0, so here is the logic that the subprocess executes. 
      $path = $cmd ["Path"]; 
      $pid = $cmd [' pid ']; 
      $total = $cmd [' Total ']; echo exec ("/usr/bin/php {$path} {$pid} {$total}"). " 
      \ n "; 
    Exit (0); 
 }}?>

Using PHP's real multi-process running mode, it is suitable for data collection, mass mailing, updating of source, TCP server and so on.

PHP has a set of process control functions (which require –enable-pcntl and POSIX extensions at compile time), enabling PHP to implement the same creation process as C in the *nix system, execute programs using the EXEC function, and process signals. Pcntl uses ticks as a signal processing mechanism (signal handle callback mechanism) to minimize the load when handling asynchronous events. What is ticks? Tick is an event that occurs every time an interpreter executes N low-level statements in a code snippet, and this snippet needs to be specified by declare.

Common PCNTL functions
1. Pcntl_alarm (int $seconds)
set a counter that sends a SIGALRM signal after a $seconds second

2. pcntl_signal (int $signo, callback $handler [, BOOL $restart _syscalls])
set up a callback function that handles the signal for $signo. Here is an example of sending a SIGALRM signal every 5 seconds and getting it from the Signal_handler function, then printing a "caught Sigalrm":


<?php
Declare (ticks = 1);
 
function Signal_handler ($signal) {
  print "caught sigalrm\n";
  Pcntl_alarm (5);
}
 
Pcntl_signal (SIGALRM, "Signal_handler", true);
Pcntl_alarm (5);
 
for (;;) {
}
 
?>

3. Pcntl_exec (string $path [, array $args [, array $envs]])
executes the specified program in the current process space, similar to the Exec family function in C. The so-called current space, that is, the code that loads the specified program overwrites the space of the current process, and completes the process of executing the program.


<?php
$dir = '/home/shankka/';
$cmd = ' ls ';
$option = ' l ';
$pathtobin = '/bin/ls ';
 
$arg = Array ($cmd, $option, $dir);
 
Pcntl_exec ($pathtobin, $arg);
echo ' 123 ';  Does not execute to the line
?>

4. Pcntl_fork (void)
creates a child process for the current process and runs the parent process first, and returns the PID of the subprocess, which is definitely greater than 0. The parent process can be paused in the code of the parent process with pcntl_wait (& $status) to know that his child process has a return value. Note: The blocking of the parent process blocks the child process at the same time. However, the end of the parent process does not affect the operation of the child process.
When the parent process runs out, it then runs the child process, which begins execution (including this function) from the statement that executes Pcntl_fork (), but at this point it returns 0 (representing a child process). It is preferable to have an exit statement in the code block of a child process that ends immediately after the child process is executed. Otherwise it will start again with some parts of the script.

Note two points:

    1. The child process is best to have an exit statement that prevents unnecessary errors;
    2. It is best not to have other statements between pcntl_fork, for example:
<?php
$pid = Pcntl_fork ();
It's best not to have other statements
if ($pid = = 1) {
  die (' could not fork ');
} else if ($pid) {
  //We are the parent
Pcntl_ Wait ($status); Protect against Zombie Children
} else {
  //We are the child
}
?>

5. pcntl_wait (int & $status [, int $options])
blocks the current process, only one child of the current process exits or receives a signal to end the current process. Use $status to return the status code of a subprocess, and you can specify a second parameter to indicate whether to call in a blocking state:
Blocking method called, the function return value is the PID of the subprocess, if no child process return value is-1;
non-blocking invocation, a function can also return 0 when a child process with a child process is running but does not end.

6. Pcntl_waitpid (int $pid, int & $status [, int $options])
features are the same as pcntl_wait, which distinguishes Waitpid as a child process that waits for the specified PID. When PID is-1 o'clock Pcntl_waitpid is the same as pcntl_wait. The state information of the subprocess is stored in the $status in the pcntl_wait and pcntl_waitpid two functions, and this parameter can be used for pcntl_wifexited, pcntl_wifstopped, pcntl_wifsignaled, Pcntl_wexitstatus, Pcntl_wtermsig, Pcntl_wstopsig, pcntl_waitpid these functions.
For example:

<?php
$pid = Pcntl_fork ();
if ($pid) {
  pcntl_wait ($status);
  $id = Getmypid ();
  echo "Parent Process,pid {$id}, child pid {$pid}\n";
} else{
  $id = Getmypid ();
  echo "Child Process,pid {$id}\n";
  Sleep (2);
}
? >

The child processes sleep for 2 seconds after the word output, and the parent process blocks until the child process exits before continuing.

7. pcntl_getpriority ([int $pid [, int $process _identifier]])
take the priority of the process, that is, the nice value, default 0, in my test environment Linux (CentOS release 5.2 (Final)), the priority is-20 to 19,-20 for the highest priority, 19 is the lowest. (20 to 20 in the manual).

8. pcntl_setpriority (int $priority [, int $pid [, int $process _identifier]])
sets the priority of the process.

9. Posix_kill
can send a signal to a process

Pcntl_singal
the callback function used to set the signal

How the child process learns of the parent process's exit when the parent process exits
When the parent process exits, the child process can generally learn from the following two simpler ways that the parent process has exited the message:

When the parent process exits, an INIT process is adopted to adopt the child process. This init process has a process number of 1, so the child process can obtain the PID of the current parent process by using getppid (). If 1 is returned, indicating that the parent process has become an init process, the original process has already been rolled out.
Use the KILL function to send an empty signal to the original parent process (Kill (PID, 0)). Use this method to check the existence of a process without actually sending a signal. So, if this function returns-1 indicates that the parent process has exited.

In addition to the above two methods, there are some implementation of more complex methods, such as the establishment of pipelines or sockets to monitor the time and so on.

Examples of PHP multi-process data acquisition

<?php/** * Project:Signfork:php Multi-line Threading * File:Signfork.class.php/Class signfork{/** * Set up the directory of child process communication files * @va
 
R string/private $tmp _path= '/tmp/';
 /** * Signfork Engine Master Boot method * 1, to determine the type of $arg, to pass the value to each child when the type is a numeric type, the number of processes to create when the type is a value. * @param object $obj Execute objects * @param string|array $arg The parameters executed by the __fork method in the object * such as: $arg, automatically decomposed into: $obj->__fork ($arg [0]), $obj-&
 Gt;__fork ($arg [1]) ... * @return Array returns an array (the child process sequence => execution result);
  */Public Function run ($obj, $arg =1) {if (!method_exists ($obj, ' __fork ')) {exit ("method ' __fork ' not found! ');
   } if (Is_array ($arg)) {$i = 0;
    foreach ($arg as $key => $val) {$spawns [$i]= $key;
    $i + +;
   $this->spawn ($obj, $key, $val);
  $spawns [' Total ']= $i;
   }elseif ($spawns =intval ($arg)) {for ($i = 0; $i < $spawns; $i + +) {$this->spawn ($obj, $i);
  }}else{exit (' bad argument! ');
   } if ($i >1000) exit (' Too many spawns! ');
  return $this->request ($spawns); /** * Signfork Master Process Control method * 1, $tmpfile determine if the child process fileexists, the child process completes and reads the content * 2, $data collects the results and data of the subprocess, and uses it to eventually return * 3, delete the subprocess file * 4, poll once for 0.03 seconds until all the child processes have finished, and then clean the child process resources * @param String|ar
  Ray $arg the ID for each subprocess @return array returns array ([child process sequence]=>[execution result]);
   * * Private Function request ($spawns) {$data =array ();
   $i =is_array ($spawns) $spawns [' Total ']: $spawns; for ($ids = 0; $ids < $i; $ids + +) {while (!) (
    $cid =pcntl_waitpid ( -1, $status, Wnohang))) Usleep (30000);
    $tmpfile = $this->tmp_path. ' Sfpid_ '. $cid;
    $data [$spawns [' Total ']? $spawns [$ids]: $ids]=file_get_contents ($tmpfile);
   Unlink ($tmpfile);
  return $data; /** * Signfork Execution method * 1, pcntl_fork build subprocess * 2, file_put_contents the "$obj->__fork ($val)" results into a specific sequence named text * 3, Posi X_kill kills the current process * @param object $obj The objects to be executed * @param the sequence ID of the $i child process, so that the corresponding data for each subprocess is returned * @param object $param for
   Input object $obj method ' __fork ' execution parameter/private function spawn ($obj, $i, $param =null) {if (Pcntl_fork () ===0) {$cid =getmypid (); File_put_contents ($this->tmp_path. ' Sfpid_ '. $cid, $obJ->__fork ($param));
   Posix_kill ($cid, sigterm);
  Exit
 }}}?>

The child processes (typically zombie processes) that PHP generates after Pcntl_fork () must be freed by the Pcntl_waitpid () function. But the Pcntl_waitpid () is not necessarily releasing the currently running process, it may be a zombie process that was generated in the past (not released), or it could be a zombie process for other visitors concurrently. However, you can use Posix_kill ($cid, sigterm) to kill the child at the end of the process.

The child process automatically copies the variables in the parent process space.

PHP Multi-Process Programming Example 2

<?php
//...
Need to install pcntl PHP extension and load it
if (function_exists ("Pcntl_fork")) {
  //generate subprocess
 $pid = Pcntl_fork ();
 if ($pid = = 1) {
  die (' could not fork ');
 } else{
  if ($pid) {
   $status = 0;
   Blocking the parent process until the subprocess is complete and not suitable for long-running scripts, using pcntl_wait ($status, 0) to implement non-blocking
   pcntl_wait ($status);
   Parent proc Code
   exit;
  else{
   //Child proc Code
   //End the current subprocess to prevent the generation of zombie process
   if (function_exists ("Posix_kill")) {
    Posix_kill ( Getmypid (), sigterm);
   else{
    System (' kill-9 '. Getmypid ());
   }
   Exit;
  }}}
else{
  //does not support multiple process processing when the code is here}//...
? >
If you do not need to block the process and want the exit state of the subprocess, you can comment out the pcntl_wait ($status) statement, or write:
 
<?php
pcntl_wait ($status, 1);
or
pcntl_wait ($status, Wnohang);
? >

In the above code, if the parent process exits (using the Exit function to exit or redirect), it causes the subprocess to become a zombie process (which is controlled by the Init process) and the child process is no longer executing.

A zombie process is a zombie process that refers to a parent process that has exited, and that process is dead after it has not been accepted by the process. (zombie) process. Any process before exiting (using exit exit) becomes a zombie process (used to hold information such as the status of the process), which is then taken over by the INIT process. If the zombie process is not recovered in time, it will occupy a process table entry in the system, and if the zombie process is too much, the last system will have no available process table entries and no more programs can be run.

There are several ways to prevent zombie processes:

1. The parent process waits for the child process to complete through functions such as wait and waitpid, and then executes the code in the parent process, which causes the parent process to hang. The above code is implemented in this way, but in a web environment it does not fit in situations where a child process needs to run for a long time (which results in a time-out).
Use the wait and Waitpid methods to enable the parent process to automatically recycle its zombie subprocess (depending on the return state of the child process), Waitpid is used for the pro-specified subprocess, and wait is for all child processes.
2. If the parent process is busy, you can install the handler with the signal function for SIGCHLD, because the parent process will receive the signal when the subprocess is finished, and you can invoke the wait recycle in handler
3. If the parent process does not care about when the subprocess ends, you can use signal (SIGCHLD, Sig_ign) to notify the kernel that you are not interested in the end of the child process, then the kernel reclaims and no longer sends a signal to the parent process, for example:

<?php
pcntl_signal (SIGCHLD, sig_ign);
$pid = Pcntl_fork ();
.... Code
?>

4. Another trick is to fork two times, the parent process fork a subprocess, and then continue to work, the child process fork a grandchild to exit, then the grandchild process is taken over by Init, after the sun process is over, Init will be recycled. However, the recycling of child processes has to do itself. Here is an example:

 #include "apue.h" #include <sys/wait.h> int main (void) {pid_t pid; if ((PID = fork ()) < 0) {Err_sys ("fork Error");} else if (PID = = 0) {/**//*/if (PID = fork ()) ;
 0) {Err_sys ("fork Error");  }elseif (PID > 0) {exit (0); /**//* parent from Second fork = =/** * We ' re the second child;
  Our parent becomes init as soon * as we real parent calls exit () in the statement above.
  * Here's where we ' d continue executing, knowing that's when * we've done, init'll reap our status.
  * * Sleep (2);
  printf ("Second child, parent PID =%d", getppid ());
Exit (0);
 
} if (Waitpid (PID, NULL, 0)!= pid)/**//* wait for the-a-child * * Err_sys ("Waitpid error"); /** * We ' re the parent (the original process);
 We continue executing, * knowing that we ' re not the parent of the second child.
* * EXIT (0); }

In the fork ()/execve () procedure, assuming that the parent process is still present at the end of the child process, and the parent process fork () has not installed the SIGCHLD signal processing function call Waitpid () to wait for the child process to end and not explicitly ignore the signal, the child process becomes a zombie process, Cannot end normally, even root identity kill-9 cannot kill zombie processes. The remedy is to kill the parent process of the zombie process (the parent process of the zombie process is inevitable), the zombie process becomes an "orphan process", and the adoptive 1th process Init,init periodically calls the wait recycle to clean up the zombie subprocess that these parent processes have exited.

So, the above example can be changed to:

<?php//////////need to install pcntl PHP extension and load it if (function_exists ("Pcntl_fork")) {//Generate first subprocess $pid = Pcntl_fork ();//$ The PID is the resulting subprocess ID if ($pid = = 1) {//subprocess fork failure Die (' could not fork ');}
 else{if ($pid) {//Parent Process Code sleep (5);//wait 5 seconds for exit (0);///$this->_redirect ('/'); }else{//first child Process code//generation grandchild Process if (($gpid = Pcntl_fork ()) < 0) {////$gpid that is the resulting grandchild process ID//grandchild process failed die (' could not fo
  RK ');
   }elseif ($gpid > 0) {//first child process code, that is, the parent process of the grandchild process $status = 0; $status = pcntl_wait ($status);
   Blocks the child process and returns the exit status of the grandchild process to check for normal exit if ($status! = 0) file_put_content (' filename ', ' grandchild process abnormal exit '); Get parent Process ID//$ppid = Posix_getppid (); If $ppid 1 indicates that its parent process has become an init process, the original parent process has exited//got the subprocess id:posix_getpid () or getmypid () or fork returned variables $pid//kill the sub process//posix_kill (GE
   Tmypid (), sigterm);
  Exit (0); }else{//namely $gpid = = 0//grandchild Process code///end the grandchild process (that is, the current process) to prevent the generation of zombie process if (function_exists (' Posix_kill ')) {Posix_k
   Ill (Getmypid (), sigterm);
   }else{system (' kill-9 '. Getmypid ());
} exit (0);  }}}else{//Does not support the code for Multi process Processing here}//...?
 >

How to create a zombie process
when a process ends its own life by invoking the Exit command, it is not actually destroyed, but rather leaves behind a data structure called the zombie process (Zombie) (System call exit, which acts as a process exit, but is limited to turning a normal process into a zombie process. , and cannot be completely destroyed). In the state of the Linux process, the zombie process is a very special one, it has abandoned almost all memory space, no executable code, can not be scheduled, only in the process list to retain a location, record the process of exit status and other information for other processes to collect, in addition, The zombie process no longer occupies any memory space. It needs its parent process to bury it, and if his parent process does not install the SIGCHLD signal handler call wait or Waitpid () waits for the child process to end and does not explicitly ignore the signal, it remains zombie, if the parent process ends, Then the init process will automatically take over the subprocess and bury it, it can still be cleared. But if the parent process is a loop and does not end, then the child process will remain zombie, which is why there are sometimes many zombie processes in the system.

No child process (except Init) disappears immediately after exit (), leaving behind a data structure called a zombie process (Zombie), which waits for the parent process to process. This is the phase that each subprocess passes through at the end of the process. If the child process does not have time to process after exit (), the status of the child process is "Z" with the PS command. If the parent process can be processed in a timely manner, it may not be possible to use the PS command to see the zombie state of the child process, but that does not mean that the subprocess does not go through zombie state.

If the parent process exits before the child process ends, the child process is taken over by Init. Init will process the child processes of the zombie state as the parent process.

In addition, you can write a php file, and then run it in the form of a later stage, for example:


<?php
//action Code public
function CreateAction () {
  //....
  Replace the args with the parameters to pass to the insertlargedata.php, separated by a space between the
  system (' Php-f insertlargedata.php '). ' args '. ' & ');
  $this->redirect ('/');
>

Then do the database operation in the insertlargedata.php file. You can also use the Cronjob + PHP way to achieve large amount of data processing.

If you are running the PHP command on a terminal, the command that you just executed will be forced to close when the terminal is closed, and you can use the Nohup command if you want it to be unaffected by the terminal shutdown:


<?php
//action Code public
function CreateAction () {
  //....
  Replace the args with the parameters to pass to the insertlargedata.php, separated by a space between the
  system (' Nohup php-f insertlargedata.php '). ' args '. ' & ');
  $this->redirect ('/');
>

You can also use the screen command instead of the Nohup command.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.