Using examples to fully explain the use of related functions of multi-process programming in PHP, PHP function _php Tutorial

Source: Internet
Author: User
Tags signal handler

Using examples to fully explain the use of the relevant functions of multi-process programming in PHP, PHP functions


PHP has a set of process control functions (which require –enable-pcntl and POSIX extensions at compile time), enabling PHP to create sub-processes like C, execute programs using the EXEC function, and process signals.

<?php header (' Content-type:text/html;charset=utf-8 ');   The extended if (!function_exists ("Pcntl_fork")) {die ("Pcntl extention is must!") must be loaded;   }//The number of total processes $totals = 3;   The number of scripts executed $CMDARR = array (); An array of the number of scripts executed 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/run.php [PID] = 0 [Total] = 3) [1] = = Array ([path] =/var/www/html/comp any/pcntl/run.php [PID] = 1 [Total] = 3) [2] = = Array ([path] =&gt ; /var/www/html/company/pcntl/run.php [PID] = 2 [Total] = 3)) */pcntl_signal (SI GCHLD, sig_ign);   If the parent process does not care what time the child process ends, the kernel is reclaimed after the child process is finished.  foreach ($cmdArr as $cmd) {$pid = Pcntl_fork ();   Create child processes//parent and child processes will execute the following code  if ($pid = =-1) {//Error handling: Returns-1 when creating a child process failure.     Die (' could not fork ');       The else if ($pid) {//parent process Gets the child process number, so here is the logic for the parent process to execute///If you do not need to block the process and want the exit state of the child process, you can comment out the pcntl_wait ($status) statement, or write: Pcntl_wait ($status, Wnohang);     Wait for the child process to break to prevent the child process from becoming a zombie process.       The else {//Sub-process gets a $pid of 0, so this is the logic that the child process executes.       $path = $cmd ["Path"];       $pid = $cmd [' pid '];       $total = $cmd [' Total ']; echo exec ("/usr/bin/php {$path} {$pid} {$total}"). "       \ n ";     Exit (0);  }}?>

Use PHP real multi-process operation mode, suitable for data collection, bulk mail, data source update, TCP server and other links.

PHP has a set of process control functions (–ENABLE-PCNTL and POSIX extensions are required at compile time), which enables PHP to create sub-processes like C in the *nix system, execute programs using the EXEC function, process signals, and so on. 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 SIGALRM signals after $seconds seconds

2. pcntl_signal (int $signo, callback $handler [, BOOL $restart _syscalls])
Set a callback function for $signo to process the signal. Here is an example of a "caught Sigalrm" that sends a SIGALRM signal every 5 seconds and is obtained by the Signal_handler function, and then prints:


<?phpdeclare (ticks = 1); function Signal_handler ($signal) {  print "caught sigalrm\n";  Pcntl_alarm (5);} Pcntl_signal (SIGALRM, "Signal_handler", True);p Cntl_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, the code that loads the specified program, overwrites the space of the current process, and the process finishes 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 first runs the parent process, returning 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 also blocks the child process. However, the end of the parent process does not affect the run of the child process.
When the parent process runs out, the child process runs, and the child process starts executing (including this function) from the statement that executes Pcntl_fork (), but at this point it returns 0 (this is a child process). It is preferable to have an exit statement in the child process's code block, which ends immediately after the child process is executed. Otherwise it will start to execute some parts of the script again.

Note two points:

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

5. pcntl_wait (int & $status [, int $options])
Blocks the current process, exiting only one child of the current process or receiving a signal to end the current process. Use $status to return the status code of a child process, and you can specify the second parameter to indicate whether to call in a blocking state:
The function returns the PID of the child process, if no child process returns a value of-1, which is called by the blocking method;
Non-blocking invocation, the function can also return 0 when there are child processes running but not ending.

6. Pcntl_waitpid (int $pid, int & $status [, int $options])
function with pcntl_wait, which differs from Waitpid as a subprocess waiting to specify PID. When the PID is-1 o'clock Pcntl_waitpid is the same as pcntl_wait. The state information of the child process is stored in the $status of the pcntl_wait and pcntl_waitpid two functions, which 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 process does not end after 2 seconds of sleep after the word output, and the parent process blocks until the child process exits and then continues to run.

7. pcntl_getpriority ([int $pid [, int $process _identifier]])
Take the priority of the process, the nice value, the default is 0, in my test environment of 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 the process

Ten. Pcntl_singal
callback function to set the signal

How the child process learns that the parent process exits when the parent process exits
When the parent process exits, the child process can generally learn from the following two simple methods that the parent process has exited the message:

When the parent process exits, there is an INIT process to adopt the child process. The process number for this init process is 1, so the child process can obtain the PID of the current parent process by using getppid (). If the return is 1, indicating that the parent process has become the INIT process, the original process has 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, 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 times and so on.

Examples of PHP multi-process data acquisition

<?php/*** Project:Signfork:php Multi-line Libraries * file:signfork.class.php*/class signfork{/** * Set the directory where the child process communication files * @var string */Private $tmp _path= '/tmp/'; /** * Signfork Engine Master Boot method * 1, determine the type of $arg, the type is an array when the value is passed to each child process, when the type is numeric, represents the number of processes to be created. * @param object $obj Execution Objects * @param string|array $arg parameters executed by the __fork method in the object * such as: $arg, automatically decomposed to: $obj->__fork ($arg [0]), $obj-&G T;__fork ($arg [1]) ... * @return Array returns an array (sub-process sequence =/Sub-process 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 whether the child process file exists, the child process is completed, and read the content * 2, $data collection of sub-process run results and data, and for the final returnBack to * 3, delete the child process file * 4, poll for 0.03 seconds, until all child processes have completed, clean up the child process resources * @param string|array $arg used to correspond to each child process ID * @return Array returns an array ([child process  Sequence]=>[sub-process 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 child Process Execution method * 1, pcntl_fork generation subprocess * 2, file_put_contents The execution result of ' $obj->__fork ($val) into a specific sequence named text * 3, Posix_kil L KILL the current process * @param object $obj objects to be executed * @param the sequence ID of an object $i child process in order to return the corresponding data for each child process * @param object $param for the input object $obj   Method ' __fork ' execution parameters */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 process (usually a zombie process) generated by PHP after Pcntl_fork () must be freed by the Pcntl_waitpid () function. But the Pcntl_waitpid () is not necessarily releasing the currently running process, it could be a zombie process that was spawned in the past (not released), or it could be a zombie process for other visitors during concurrency. However, you can use Posix_kill ($cid, SIGTERM) to kill it at the end of the child process.

The child process automatically replicates 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 child process $pid = Pcntl_fork (); if ($pid = = -1) {die  (' could not fork ');} else{  if ($pid) {   $status = 0;   Block the parent process until the child process is finished, not suitable for long-running scripts, and use Pcntl_wait ($status, 0) to implement the non-blocking   pcntl_wait ($status);   Parent proc Code   exit;  } else{   //Child proc Code   //ends the current subprocess to prevent the spawning of the zombie process   if (function_exists ("Posix_kill")) {    Posix_kill ( Getmypid (), SIGTERM);   } else{    System (' kill-9 '. Getmypid ());   }   Exit;  } }}else{  //Does not support multi-process processing when the code here}//... > If you do not need to block the process and want the exit status of the child process, you can comment out the pcntl_wait ($status) statement, or write: <?phppcntl_wait ($status, 1);//or Pcntl_wait ($ status, Wnohang);? >

In the preceding code, if the parent process exits (using the Exit function to exit or redirect), it causes the child process to become a zombie process (which is given to the Init Process Control) and the child process is no longer executing.

A zombie process is a zombie process in which a parent process has exited, and the process dead after it has not been accepted by the process. (zombie) process. Any process that exits before exiting (using exit exit) becomes a zombie process (used to hold information such as the state of the process) and is then taken over by the INIT process. If the zombie process is not recycled in time, it will occupy a process table entry in the system, and if the zombie process is too large, the system will not be able to use the process table entries, so it can no longer run other programs.

There are several ways to prevent the zombie process:

1. The parent process waits for the child process to finish by waiting for a function such as wait and waitpid, and then executes the code in the parent process, which causes the parent process to hang. The code above is implemented in this way, but in a web environment, it is not suitable for long-running situations (which can cause timeouts) for child processes.
Use the wait and Waitpid methods to enable the parent process to automatically reclaim its zombie subprocess (depending on the return status of the child process), Waitpid is used for the temporary control of the specified subprocess, and wait is for all child processes.
2. If the parent process is busy, you can use the signal function to install handler for SIGCHLD, because the parent process will receive the signal when the child process ends, and you can call the wait recycle in handler
3. If the parent process does not care about when the child process ends, the kernel can be notified with signal (SIGCHLD, sig_ign), and the end of the child process is not interested, then the kernel recycles and no longer sends a signal to the parent process, such as:

<?phppcntl_signal (SIGCHLD, sig_ign); $pid = Pcntl_fork ();//....code?>

4. There is also a trick, that is, fork two times, the parent process fork a child process, and then continue to work, the child process and then fork a grandchild process to exit, then the Sun process is init takeover, after the end of the sun process, init will be recycled. But the recycling of the sub-process to do it yourself. Here is an example:

 #include "apue.h" #include 
  
    int main (void) {pid_t pid; if (pid = fork ()) < 0) {Err_ SYS ("fork error");} else if (PID = = 0) {/**//* First child */if (PID = fork ()) < 0) {Err_sys ("fork Error");}  ElseIf (PID > 0) {exit (0); /**//* parent from Second fork = = First child */}/** * 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 if * we ' re done, Init would reap our status.  */Sleep (2);  printf ("Second child, parent PID =%d", getppid ()); Exit (0);} if (Waitpid (PID, NULL, 0)! = pid)/**//* wait for first child */Err_sys ("Waitpid error"); /** * We ' re the parent (the original process); We continue executing, * knowing that we don't have 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 that the parent process fork () is not installed before the SIGCHLD signal handler call Waitpid () waits for the child process to end without explicitly ignoring the signal, the child process becomes a zombie process, Does not end normally, even the root identity kill-9 cannot kill the zombie process. The remedy is to kill the parent process of the zombie process (the parent process of the zombie process must exist), the zombie process becomes the "orphan process", adoptive to the 1th process Init,init will periodically call the wait recycle cleanup These parent processes have exited the zombie subprocess.

Therefore, the above example can be changed to:

<?php//.....//need to install pcntl PHP extension and load it if (function_exists ("Pcntl_fork")) {//Generate first child process $pid = Pcntl_fork ();//$ PID is the resulting sub-process idif ($pid = =-1) {//Sub-process fork failure die (' could not fork ');} else{if ($pid) {//Parent Process Code sleep (5);//wait 5 seconds exit (0);//or $this->_redirect ('/');}  else{///first child Process code//Generate grandchild Process if (($gpid = Pcntl_fork ()) < 0) {////$gpid that is, the resulting grandchild process ID//grandchild process produces a failure die (' could not fork ');   }elseif ($gpid > 0) {//first child process code, which 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, which is used to check if the normal exit if ($status! = 0) file_put_content (' filename ', ' sun-process exception exit '); Get parent Process ID//$ppid = Posix_getppid (); If $ppid is 1, it indicates that its parent process has become the INIT process, the original parent process has exited//Gets the child process id:posix_getpid () or getmypid () or the variable returned by fork $pid//kill the child process//posix_kill (   Getmypid (), SIGTERM);  Exit (0); }else{//ie $gpid = = 0//Sun Process Code//....//end grandchild process (that is, current process) to prevent the spawning of the zombie process if (function_exists (' Posix_kill ')) {Posix_kill (g   Etmypid (), SIGTERM);   }else{system (' kill-9 '. Getmypid ());  } exit (0); }}}}else{//Do not support multi-process processing when the code here}//... &gT 

How to produce a zombie process
When a process calls the Exit command to end its own life, it is not actually destroyed, but rather leaves behind a data structure called the zombie process (Zombie) (System call exit, which is the function of making the process exit, but only to turn 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, and can not be scheduled, just keep a position in the process list, record the process's 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, 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, then it remains zombie state, if the parent process is over, Then the init process will automatically take over the child process, and for it to corpse, it can still be cleared. But if the parent process is a loop and does not end, then the child process will remain zombie state, which is why there are sometimes many zombie processes in the system.

Any child process (except Init) after exit () does not disappear immediately, leaving behind a data structure called the zombie process (Zombie), waiting for the parent process to handle it. This is the stage at which each child process passes at the end. If the child process has not been processed by the parent process after exit (), then the PS command will be able to see the status of the child process as "Z". If the parent process can be processed in a timely manner, it may be too late to see the zombie state of the child process with the PS command, but this does not mean that the child process 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 process of the zombie state as the parent process.

Alternatively, you can write a php file and then run it in a later form, for example:


<?php//action Code Public Function createaction () {  //....  Replace args with the parameter to pass to insertlargedata.php, with the space between the parameters  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 method to achieve large data volume processing.

If you are running PHP commands at the terminal, when the terminal is closed, the command just executed will also be forced to close, if you want it to be unaffected by terminal shutdown, you can use the Nohup command to implement:


<?php//action Code Public Function createaction () {  //....  Replace args with the parameters to pass to insertlargedata.php, with the space between the parameters  system (' Nohup php-f insertlargedata.php '. ' args '. ' & ');  $this->redirect ('/');}? >

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

http://www.bkjia.com/PHPjc/1049141.html www.bkjia.com true http://www.bkjia.com/PHPjc/1049141.html techarticle using examples to fully explain the use of the relevant functions of multi-process programming in PHP, PHP function PHP has a set of process control functions (compile-time needs –enable-pcntl and POSIX extension), so that PHP can be implemented with C ...

  • Related Article

    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.