In-depth Exploration of PHP multi-process programming methods

Source: Internet
Author: User
This article mainly introduces the multi-process programming method of PHP in depth, and introduces the multi-thread attempt in Windows, which is an important part of PHP concurrency implementation. For more information, see Create a sub-process
Generally, the sub-process is written as follows:

<? Php $ pid = pcntl_fork (); if ($ pid =-1) {// creation failure die ('could not fork');} else {if ($ pid) {// The code written here is the exit ("parent! ");} Else {// sub-process code. to prevent the use of sub-processes from exhausting system resources, add exit to ensure that the sub-process exits normally. Exit ("child") ;}}?>

If the above code successfully creates a sub-process, the system has two processes, one is the parent process, the other is the sub-process, and the sub-process ID is $ pid. When the system runs to $ pid = pcntl_fork ();, the parent and child processes start to run their respective program codes. The running result of the code is parent and child. it's strange, why is the result output in a code that is mutually exclusive between if and else? As mentioned above, when the code is in pcntl_fork, a parent process runs parent and a child process runs child. The code results show parent and child. As for who is first and who is later, it depends on the allocation of system resources.

If you need multiple processes to process data, you can start sub-processes according to the number of data, for example, 1000 processes. Use the for loop.

# If the total number is less than or equal to 0, wait for 60 seconds and exit if ($ count <= 0) {sleep (60); exit ;}# if it is greater than 1000, calculate the number of processes required. if ($ count> 1000) {$ cycleSize = ceil ($ count/1000);} else {$ cycleSize = 1 ;} for ($ I = 0; $ I <$ cycleSize; $ I ++) {$ pid = pcntl_fork (); if ($ pid =-1) {break ;} else {if ($ pid) {# the parent process obtains the pid of the child process and stores it in the array $ pidArr [] = $ pid;} else {// start sending, after the sub-process executes its own task, it exits. Exit ;}}while (count ($ pidArr)> 0) {$ myId = pcntl_waitpid (-1, $ status, WNOHANG ); foreach ($ pidArr as $ key => $ pid) {if ($ myId = $ pid) unset ($ pidArr [$ key]);}

Then, use crontab to make the PHP program automatically run at intervals.

Of course, the sample code is relatively simple. you also need to consider how to prevent multiple sub-processes from executing the same piece of data or starting to execute the php file to enable new processes when the current process has not completed data processing.


PHP multi-process implementation
The following describes how to implement PHP multi-process:

1. direct mode

Pcntl_fork () creates a process. The return value of the parent process is the pid of the child process, and the return value of the child process is 0.-1 indicates that the process fails to be created. Similar to C.

Test. php

<?php  // example of multiple processes  date_default_timezone_set( 'Asia/Chongqing');  echo "parent start, pid ", getmypid(), "\n" ;  beep();  for ($i=0; $i<3; ++$i){     $pid = pcntl_fork();      if ($pid == -1){         die ("cannot fork" );     } else if ($pid > 0){         echo "parent continue \n";         for ($k=0; $k<2; ++$k){           beep();        }     } else if ($pid == 0){         echo "child start, pid ", getmypid(), "\n" ;         for ($j=0; $j<5; ++$j){           beep();        }         exit ;     }  }  // ***  function beep(){      echo getmypid(), "\t" , date( 'Y-m-d H:i:s', time()), "\n" ;     sleep(1);  }?>

Run the command line

#php -f test.php

Output result

parent start, pid 17931793  2013-01-14 15:04:17parent continue1793  2013-01-14 15:04:18child start, pid 17941794  2013-01-14 15:04:181794  2013-01-14 15:04:191793  2013-01-14 15:04:191794  2013-01-14 15:04:20parent continue1793  2013-01-14 15:04:20child start, pid 17951795  2013-01-14 15:04:2017931794        2013-01-14 15:04:212013-01-14 15:04:211795  2013-01-14 15:04:211794  2013-01-14 15:04:221795  2013-01-14 15:04:22parent continue1793  2013-01-14 15:04:22child start, pid 17961796  2013-01-14 15:04:221793  2013-01-14 15:04:231796  2013-01-14 15:04:231795  2013-01-14 15:04:231795  2013-01-14 15:04:241796  2013-01-14 15:04:241796  2013-01-14 15:04:251796  2013-01-14 15:04:26

We can see that three sub-processes are created and run in parallel with the parent process. The format of one row is somewhat different from that of others,
17931794 15:04:21
The two processes perform write operations at the same time, causing a conflict.


2. blocking mode

Directly, after the parent process creates a child process, it does not wait until the child process ends, but continues to run. It seems that there is no problem here. If the php script does not automatically end after running, but resident memory, the sub-process cannot be recycled. That is, botnets. You can use the pcntl_wai () method to wait for the process to end, and then recycle the process that has already ended.
Change the test script:

$pid = pcntl_fork();if ($pid == -1){  ...} else if ($pid > 0){   echo "parent continue \n";   pcntl_wait($status);   for ($k=0; $k<2; ++$k){     beep();  }} else if ($pid == 0){   ...}

Run the command line

#php -f test.php

Output result

parent start, pid 18071807  2013-01-14 15:20:05parent continuechild start, pid 18081808  2013-01-14 15:20:061808  2013-01-14 15:20:071808  2013-01-14 15:20:081808  2013-01-14 15:20:091808  2013-01-14 15:20:101807  2013-01-14 15:20:111807  2013-01-14 15:20:12parent continuechild start, pid 18091809  2013-01-14 15:20:131809  2013-01-14 15:20:141809  2013-01-14 15:20:151809  2013-01-14 15:20:161809  2013-01-14 15:20:171807  2013-01-14 15:20:181807  2013-01-14 15:20:19child start, pid 18101810  2013-01-14 15:20:20parent continue1810  2013-01-14 15:20:211810  2013-01-14 15:20:221810  2013-01-14 15:20:231810  2013-01-14 15:20:241807  2013-01-14 15:20:251807  2013-01-14 15:20:26

The parent process blocks itself in pcntl_wait () and runs only after the child process is finished.


3. non-blocking

The blocking method loses the concurrency of multiple processes. There is also a way to recycle the child processes that have already been completed, and to run them in parallel. This is a non-blocking method.
Modify script:

<?php  // example of multiple processes  date_default_timezone_set( 'Asia/Chongqing');  declare (ticks = 1);  pcntl_signal(SIGCHLD, "garbage" );  echo "parent start, pid ", getmypid(), "\n" ;  beep();  for ($i=0; $i<3; ++$i){     $pid = pcntl_fork();      if ($pid == -1){         die ("cannot fork" );     } else if ($pid > 0){         echo "parent continue \n";         for ($k=0; $k<2; ++$k){           beep();        }     } else if ($pid == 0){         echo "child start, pid ", getmypid(), "\n" ;         for ($j=0; $j<5; ++$j){           beep();        }         exit (0);     }  }  // parent  while (1){      // do something else     sleep(5);  }  // ***  function garbage($signal){      echo "signel $signal received\n" ;            while (($pid = pcntl_waitpid(-1, $status, WNOHANG))> 0){         echo "\t child end pid $pid , status $status\n" ;     }  }  function beep(){      echo getmypid(), "\t" , date( 'Y-m-d H:i:s', time()), "\n" ;     sleep(1);  }?>

Run the command line

#php -f test.php &

Output result

parent start, pid 20662066  2013-01-14 16:45:34parent continue2066  2013-01-14 16:45:35child start, pid 20672067  2013-01-14 16:45:3520662067        2013-01-14 16:45:362013-01-14 16:45:362067  2013-01-14 16:45:37parent continue2066  2013-01-14 16:45:37child start, pid 20682068  2013-01-14 16:45:372067  2013-01-14 16:45:382068  2013-01-14 16:45:382066  2013-01-14 16:45:38parent continue2066  2013-01-14 16:45:40child start, pid 20692069  2067  2013-01-14 16:45:402013-01-14 16:45:402068  2013-01-14 16:45:402066  2013-01-14 16:45:412069  2013-01-14 16:45:412068  2013-01-14 16:45:41signel 17 received     child end pid 2067, status 02069  2013-01-14 16:45:422068  2013-01-14 16:45:422069  2013-01-14 16:45:43signel 17 received     child end pid 2068, status 02069  2013-01-14 16:45:44signel 17 received     child end pid 2069, status 0

Multiple processes run concurrently. after about 10 seconds, run ps-ef | grep php to check the running process. there is only one process.
Lqling 2066 1388 0 00:00:00 pts/1 php-f t5.php
It is the parent process, and the child process is recycled.


Sub-process exit status

pcntl_waitpid(-1, $status, WNOHANG) $status

Returns the end status of the sub-process.


Multithreading in windows

Windows does not support the pcntl function. Fortunately, the tool curl_multi_exec () uses internal multithreading to access multiple links. each link can be used as a task.

Write the script test1.php

<?php  date_default_timezone_set( 'Asia/Chongqing');  $tasks = array(     'http://localhost/feedbowl/t2.php?job=task1',     'http://localhost/feedbowl/t2.php?job=task2',     'http://localhost/feedbowl/t2.php?job=task3'  );  $mh = curl_multi_init();  foreach ($tasks as $i => $task){     $ch[$i] = curl_init();     curl_setopt($ch[$i], CURLOPT_URL, $task);     curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1);     curl_multi_add_handle($mh, $ch[$i]);  }  do {$mrc = curl_multi_exec($mh,$active); } while ($mrc == CURLM_CALL_MULTI_PERFORM);  while ($active && $mrc == CURLM_OK) {     if (curl_multi_select($mh) != -1) {      do {$mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM);     }  }  // completed, checkout result  foreach ($tasks as $j => $task){     if (curl_error($ch[$j])){       echo "task ${j} [$task ] error " , curl_error($ch[$j]), "\r\n" ;     } else {       echo "task ${j} [$task ] get: \r\n" , curl_multi_getcontent($ch[$j]), "\r\n" ;     }  }?>

Write the script test2.php

<?php  date_default_timezone_set( 'Asia/Chongqing');  echo "child start, pid ", getmypid(), "\r\n" ;  for ($i=0; $i<5; ++$i){     beep();  }  exit (0);  // ***  function beep(){    echo getmypid(), "\t" , date('Y-m-d H:i:s' , time()), "\r\n";    sleep(1);  }?>

Run the command line

#php -f test1.php &

Output result

task 0 [http://localhost/feedbowl/t2.php?job=task1] get:child start, pid 58045804  2013-01-15 20:22:355804  2013-01-15 20:22:365804  2013-01-15 20:22:375804  2013-01-15 20:22:385804  2013-01-15 20:22:39task 1 [http://localhost/feedbowl/t2.php?job=task2] get:child start, pid 58045804  2013-01-15 20:22:355804  2013-01-15 20:22:365804  2013-01-15 20:22:375804  2013-01-15 20:22:385804  2013-01-15 20:22:39task 2 [http://localhost/feedbowl/t2.php?job=task3] get:child start, pid 58045804  2013-01-15 20:22:355804  2013-01-15 20:22:365804  2013-01-15 20:22:375804  2013-01-15 20:22:385804  2013-01-15 20:22:39

As shown in the print TIME, multiple tasks run almost simultaneously.

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.