Deep analysis of (pseudo) multithreading and multi-process _php techniques in PHP

Source: Internet
Author: User
Tags fread

(pseudo) Multithreading: the use of external forces
Using the Web server itself multithreading to handle, from the Web server multiple calls we need to implement multithreaded program.
QUOTE:
We know that PHP itself does not support multithreading, but our Web server supports multithreading.
That is, it can be accessed by more than one person at a time. This is also my PHP in the implementation of multithreading in the foundation.
Let's say we're running a.php this file. But I also requested the Web server to run another b.php in the program
Then these two files will be executed concurrently.
(PS: After a link request is sent, the Web server executes it, regardless of whether the client has exited)
Sometimes, we want to run not another file, but a part of the code in this file. What should we do?
In fact, it is through the parameters to control a.php to run which section of the program.
Let's look at an example:

Copy Code code as follows:

<?php
function Runthread () {
$fp = Fsockopen (' localhost ', $errno, $errmsg);
Fputs ($fp, "get/a.php?act=brnrn");//The second parameter here is the request header specified in the HTTP protocol. See the definition in RFC
Fclose ($FP);
}
function A () {
$fp = fopen (' Result_a.log ', ' W ');
Fputs ($fp, ' Set in '. Date (' H:i:s ', Time ()). (double) microtime (). "RN");
Fclose ($FP);
}
Function B () {
$fp = fopen (' Result_b.log ', ' W ');
Fputs ($fp, ' Set in '. Date (' H:i:s ', Time ()). (double) microtime (). "RN");
Fclose ($FP);
}
if (!isset ($_get[' act ')) {$_get[' act ' = ' a ';};
if ($_get[' act '] = = ' a ') {
Runthread ();
A ();
}else if ($_get[' act '] = = ' B ') {
b ();
};
?>

Open Result_a.log and Result_b.log to compare the time of access in two files. As you can see, these two are actually running on different threads. Some time is exactly the same.
The above is just a simple example that can be improved into other forms.
Since PHP can also be more than a thread, then the problem has come, that is the problem of synchronization. We know that PHP itself does not support multithreading. So there won't be anything like The synchronize method in Java. So how do we do that?

1. Try not to access the same resources. To avoid conflicts. However, you can operate as a database at the same time. Because the database is a concurrency-enabled operation. So in the multithreaded PHP
Do not write data to the same file. If you have to write, use a different method to sync. such as calling flock to lock the file. or create a temporary file and wait for the file to disappear while in another thread (file_exits (' xxx ')); This is equal to the presence of this temporary file, which means that the thread is actually working, and if this file is not present, other threads have released this.

2. Try not to read the data from the socket after the execution of the fputs from Runthread. Because to implement multithreading, you need to use non-blocking mode. That is, it returns immediately when a function like fgets ... So reading and writing data can be problematic. If you use blocking mode, the program is not multi-threaded. He will wait until the above return to execute the following program. So if you need to exchange data, you end up using outside files or data. If you really want it, use Socket_set_nonblock ($FP) to achieve it.

Having said so much, does this have any practical significance? When does this need to be used in this way?
The answer is yes. You know. In a continuous reading of network resources, the speed of the network is the bottleneck. If you use this form, you can read different pages simultaneously with multiple threads.

I do a can from 8848, Soaso these mall website search information program. There is also a program that reads business information and company catalogs from Alibaba's website. Because both programs are constantly linking their servers to read the information and save it to the database. The use of this technique eliminates the bottleneck in waiting for a response.

Multi-process: Using PHP's Process Control functions (pcntl/threading function)
Only used in Unix like Os,windows is not available.
When compiling PHP, you need to add--enable-pcntl, and it is recommended that you run only in CLI mode and not in a Web server environment.
The following is a short test code:

Copy Code code as follows:

Declare (Ticks=1);
$bWaitFlag = FALSE; Whether to wait for the process to end
$intNum = 10; Total Processes
$pids = Array (); Process PID Arrays
Echo ("start\n");
for ($i = 0; $i < $intNum; $i + +) {
$pids [$i] = Pcntl_fork ();///produces the subprocess and runs the code from under the current line and does not inherit the data information from the parent process
if (! $pids [$i]) {
Child process Process Code snippet _start
$str = "";
Sleep (5+ $i);
For ($j =0 $j < $i; $j + +) {$str. = "*";}
echo "$i->". Time (). "$str \ n";
Exit ();
Child process Process Code snippet _end
}
}
if ($bWaitFlag)
{
for ($i = 0; $i < $intNum; $i + +) {
Pcntl_waitpid ($pids [$i], $status, wuntraced);
echo "Wait $i->". Time (). "\ n";
}
}
Echo ("end\n");

The results of the operation are as follows:
Code:[copy Toclipboard][qiao@oicq qiao]$ phptest.php
Start
End
[Qiao@oicq qiao]$ Ps-aux | grep "PHP"
Qiao 32275 0.0 0.5 49668 6148pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32276 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32277 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32278 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32279 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32280 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32281 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32282 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32283 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32284 0.0 0.5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b
Qiao 32286 0.0 0.0 1620 600pts/1 S 14:03 0:00 grep php
[Qiao@oicq qiao]$ 0-> 1133503401
1-> 1133503402 *
2-> 1133503403 * *
3-> 1133503404 * * *
4-> 1133503405 * * *
5-> 1133503406 * * *
6-> 1133503407 Hu Jintao
7-> 1133503408 *******
8-> 1133503409 ********
9-> 1133503410 *********
[Qiao@oicq qiao]$
If $bwaitflag=ture, the result is as follows:
Code:[copy Toclipboard][qiao@oicq qiao]$ phptest.php
Start
0-> 1133503602
Wait 0-> 1133503602
1-> 1133503603 *
Wait 1-> 1133503603
2-> 1133503604 * *
Wait 2-> 1133503604
3-> 1133503605 * * *
Wait 3-> 1133503605
4-> 1133503606 * * *
Wait 4-> 1133503606
5-> 1133503607 * * *
Wait 5-> 1133503607
6-> 1133503608 Hu Jintao
Wait 6-> 1133503608
7-> 1133503609 *******
Wait 7-> 1133503609
8-> 1133503610 ********
Wait 8-> 1133503610
9-> 1133503611 *********
Wait 9-> 1133503611
End
[Qiao@oicq qiao]$
As can be seen from the examples of multiple processes, after using Pcntl_fork (), a child process is generated, and the code that runs the child process starts with the code after Pcntl_fork (), and the child process does not inherit the data information from the parent process (which actually makes a completely new copy of the parent process's data), Therefore, use if (! $pids [$i]) to control the code snippets that the child process actually runs.
For a more detailed study, for the time being, you can refer to the link to my manual.

[Article II] try PHP command-line scripting multi-process concurrent execution
In addition to fork, there is another way of concurrency under the CLI, see my example:
PHP does not support multithreading, but we can translate the problem into "multiple processes" to solve. Because pcntl_fork in PHP is only available on UNIX platforms, this article attempts to use Popen instead.
Here is an example:
Subroutine code that is called in parallel:

Copy Code code as follows:

<?php
if ($ARGC ==1) {
Echo ("argv\n");
}
$arg = $argv [1];
For ($i =0 $i <10; $i + +)
{
Echo ($i.). 1. ". Time ()." Exec $arg \ n ");
if ($arg = = ' PhP2 ') {
Sleep (1);
Echo ($i.). 2. ". Time ()." Exec $arg \ n ");
Sleep (1);
}else{
Sleep (1);
}
}
?>

The main caller program, by which he invokes the child process, and concurrently the output of the collection subroutine
Copy Code code as follows:

Error_reporting (E_all);
$handle 1 = popen (' php sub.php php1 ', ' R ');
$handle 2 = popen (' php sub.php php2 ', ' R ');
$handle 3 = Popen (' php sub.php php3 ', ' R ');
echo "' $handle 1 ';". GetType ($handle 1). "\ n";
echo "' $handle 2 ';". GetType ($handle 2). "\ n";
echo "' $handle 3 ';". GetType ($handle 3). "\ n";
Sleep (20);
while (!feof ($handle 1) | |!feof ($handle 2) | | |!feof ($handle 3))
{
$read = fgets ($handle 1);
Echo $read;
$read = Fgets ($handle 2);
Echo $read;
$read = fgets ($handle 3);
Echo $read;
}
Pclose ($handle 1);
Pclose ($handle 2);
Pclose ($handle 3);

Here is the output on my machine:
c:\my_hunter>php exec.php
' Resource ID #4 '; Resource
' Resource ID #5 '; Resource
' Resource ID #6 '; Resource
0.1.1147935331 exec Php1
0.1.1147935331 exec PhP2
0.1.1147935331 exec php3
1.1.1147935332 exec Php1
0.2.1147935332 exec PhP2
1.1.1147935332 exec php3
2.1.1147935333 exec Php1
1.1.1147935333 exec PhP2
2.1.1147935333 exec php3
3.1.1147935334 exec Php1
1.2.1147935334 exec PhP2
3.1.1147935334 exec php3
4.1.1147935335 exec Php1
2.1.1147935335 exec PhP2
4.1.1147935335 exec php3
5.1.1147935336 exec Php1
2.2.1147935336 exec PhP2
5.1.1147935336 exec php3
6.1.1147935337 exec Php1
3.1.1147935337 exec PhP2
6.1.1147935337 exec php3
7.1.1147935338 exec Php1
3.2.1147935338 exec PhP2
7.1.1147935338 exec php3
8.1.1147935339 exec Php1
4.1.1147935339 exec PhP2
8.1.1147935339 exec php3
9.1.1147935340 exec Php1
4.2.1147935340 exec PhP2
9.1.1147935340 exec php3
5.1.1147935341 exec PhP2
5.2.1147935342 exec PhP2
6.1.1147935343 exec PhP2
6.2.1147935344 exec PhP2
7.1.1147935345 exec PhP2
7.2.1147935346 exec PhP2
8.1.1147935347 exec PhP2
8.2.1147935348 exec PhP2
9.1.1147935349 exec PhP2
9.2.1147935350 exec PhP2
* * Summary: * *
* * Main program cycle waiting for the child process, through the fgets or fread process output to obtain, from the time stamp, it is true that the implementation of concurrency. **
-----------------------------------------------
Future Improvements:
* Popen open handle is one-way, if you need to interact with the child process, you can use the Proc_open
* Using arrays and child functions instead of while (!feof ($handle 1) | |!feof ($handle 2) | | |!feof ($handle 3)
* Use fread Once the process has produced output to finish, not one line at a time.
A concurrent Execution Shell Task Scheduler, this program reads a task file, the inside of each line of command concurrent execution, you can set the number of concurrent child processes:
Copy Code code as follows:

/*
Chief Manager
Concurrent task List of execution subtasks
*/
Include (".. /common/conf.php ");
Include (".. /common/function.php ");
Number of processes turned on
$exec _number = 40;
/***** Main ********/
if ($ARGC ==1) {
Echo ("argv\n");
}
$taskfile = $argv [1];
Tasklist
$tasklist = file ($taskfile);
$tasklist _len = count ($tasklist);
$tasklist _pos = 0;
$handle _list = Array ();
while (1)
{
If the list of child processes is idle, populate the complete list of child processes
if ($exec _number > count ($handle _list) &&
$tasklist _pos < $tasklist _len)
{
for ($i = $tasklist _pos; $i < $tasklist _len;)
{
$command = $tasklist [$i];
$handle _list[] = Popen ($command, "R");
Tolog ("Begin task \ t". $tasklist [$i]);
$i + +;
if ($exec _number = = count ($handle _list)) break;
}
$tasklist _pos = $i;
}
If the child process list is empty, exit
if (0 = = count ($handle _list))
{
Break
}
Check the output of the list of child processes and close and record the stopped child process
$end _handle_keys = Array ();
foreach ($handle _list as $key => $handle)
{
$str = Fgets ($handle, 65536);
$str = Fread ($handle, 65536);
Echo ($STR);
if (feof ($handle))
{
$end _handle_keys[] = $key;
Pclose ($handle);
}
}
Kick out of a stopped child process
foreach ($end _handle_keys as $key)
{
unset ($handle _list[$key]);
Var_dump ($handle _list);
Exit
}
}
Tolog ("\n\n*******************end**********************\n\n", "", true);

attach a section of the socket multiple process received code:
Copy Code code as follows:

do {
if ($msgsock = socket_accept ($sock)) < 0) {
echo "Socket_accept () Failed:reason:". Socket_strerror ($msgsock). "\ n";
Break
}
$pid = Pcntl_fork ();
if ($pid = = 1) {
Die (' could not fork ');
else if (! $pid) {
.....
Socket_write ($msgsock, $msg, strlen ($msg));
do {
......
} while (true);
Socket_close ($msgsock);
}
} while (true);

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.