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.