Is there a way to implement multithreading in php? Suppose you are writing a php application based on multiple servers. Ideally, you can send requests to multiple servers at the same time, instead of one server after another. Can it be implemented? The answer is yes, of course. The answer is as follows:
When someone wants to implement the concurrency function, they usually think of using fork or spawn.
Threads, but when they find that php does not support multithreading, they will probably switch their thinking to use some bad languages, such as perl.
In fact, in most cases, you do not need to use fork or thread, and you will get better performance than using fork or thread.
Suppose you want to create a service to check the running n servers to make sure they are still running normally. You may write the following code:
The code is as follows:
$ Hosts = array ("host1.sample.com", "host2.sample.com", "host3.sample.com ");
$ Timeout = 15; $ status = array ();
Foreach ($ hosts as $ host ){
$ Errno = 0;
$ Errstr = "";
$ S = fsockopen ($ host, 80, $ errno, $ errstr, $ timeout );
If ($ s ){
$ Status [$ host] = "Connectedn ";
Fwrite ($ s, "HEAD/HTTP/1.0 rnHost: $ hostrnrn ");
Do {
$ Data = fread ($ s, 8192 );
If (strlen ($ data) = 0) {break ;}
$ Status [$ host]. = $ data;
} While (true); fclose ($ s );
} Else {
$ Status [$ host] = "Connection failed: $ errno $ errstrn ";
}
}
Print_r ($ status );
?>
It runs well, but it takes a long time to expand the code to manage a large number of servers before fsockopen () analyzes the hostname and establishes a successful connection (or delay $ timeout seconds.
Therefore, we must discard this code; we can establish an asynchronous connection-no need to wait for fsockopen to return the connection status. PHP still needs to parse the hostname (so it is more wise to directly use the ip address), but it will return immediately after opening a connection, and then we can connect to the next Server.
There are two ways to achieve this. in PHP5, you can use the newly added stream_socket_client () function to directly replace fsocketopen (). In versions earlier than PHP5, you need to do it yourself and use the sockets extension to solve the problem.
The solution in PHP5 is as follows:
The code is as follows:
$ Hosts = array ("host1.sample.com", "host2.sample.com", "host3.sample.com ");
$ Timeout = 15;
$ Status = array ();
$ Sockets = array ();
Foreach ($ hosts as $ id => $ host ){
$ S = stream_socket_client ("$ host: 80", $ errno, $ errstr, $ timeout, STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT );
If ($ s ){
$ Sockets [$ id] = $ s;
$ Status [$ id] = "in progress ";
} Else {
$ Status [$ id] = "failed, $ errno $ errstr ";
}
}
While (count ($ sockets )){
$ Read = $ write = $ sockets;
$ N = stream_select ($ read, $ write, $ e = null, $ timeout );
If ($ n> 0 ){
Foreach ($ read as $ r ){
$ Id = array_search ($ r, $ sockets );
$ Data = fread ($ r, 8192 );
If (strlen ($ data) = 0 ){
If ($ status [$ id] = "in progress "){
$ Status [$ id] = "failed to connect ";
}
Fclose ($ r );
Unset ($ sockets [$ id]);
} Else {
$ Status [$ id]. = $ data;
}
}
Foreach ($ write as $ w ){
$ Id = array_search ($ w, $ sockets );
Fwrite ($ w, "HEAD/HTTP/1.0 rnHost:". $ hosts [$ id]. "rnrn ");
$ Status [$ id] = "waiting for response ";
}
} Else {
Foreach ($ sockets as $ id => $ s ){
$ Status [$ id] = "timed out". $ status [$ id];
}
Break;
}
}
Foreach ($ hosts as $ id => $ host ){
Echo "Host: $ hostn"; echo "Status:". $ status [$ id]. "nn ";
}
?>
We use stream_select () to wait for the connection event opened by sockets. Stream_select () calls the system's select (2) function to work: the first three parameters are the array of the streams you want to use; you can read them, an error occurred while writing and retrieving data (three parameters respectively ). Stream_select () you can set the $ timeout (second) parameter to wait for the event to happen-when the event occurs, the corresponding sockets data will be written into your input parameters.
The following is the implementation of PHP4.1.0 and later versions. if you have compiled PHP with sockets (ext/sockets) support, you can use the same code as the root, the preceding functions of the streams/filesystem function must be implemented using the ext/sockets function. The main difference is that we use the following function instead.
Stream_socket_client () to establish a connection:
The code is as follows:
// This value is correct for Linux, other systems have other values
Define ('einss SS', 115 );
Function non_blocking_connect ($ host, $ port, & $ errno, & $ errstr, $ timeout ){
$ Ip = gethostbyname ($ host );
$ S = socket_create (AF_INET, SOCK_STREAM, 0 );
If (socket_set_nonblock ($ s )){
$ R = @ socket_connect ($ s, $ ip, $ port );
If ($ r | socket_last_error () = EINPROGRESS ){
$ Errno = EINPROGRESS; return $ s;
}
}
$ Errno = socket_last_error ($ s );
$ Errstr = socket_strerror ($ errno );
Socket_close ($ s );
Return false;
}
?>
Replace stream_select () with socket_select (), replace fread () with socket_read (), and use
Replace socket_write () with fwrite () and replace fclose () with socket_close () to execute the script!
PHP5 is advanced in that you can use stream_select () to process almost all streams. for example, you can use include
STDIN uses it to receive keyboard input and save it to an array. you can also receive data in the pipeline opened through proc_open.
If you want PHP4.3.x to have its own streams processing function, I have prepared a patch for you that allows fsockopen to work asynchronously. I do not agree to use this patch. this patch will not appear in the official PHP version. I included the implementation of the stream_socket_client () function in the patch, you can make your script compatible
PHP5.