Many PHP developers believe that, because the standard PHP lacks the thread function, it is impossible for the actual PHP application to execute multi-task processing. For example, if an application requires information from other Web sites, it must be stopped before the remote retrieval is complete. This is wrong! This article describes how to use stream_select and stream_socket_client to implement multi-task PHP processing in the process.
PHP does not support threads. Even so, in contrast to what most PHP developers believe, PHP applications can perform multitasking. Let's start to describe the meaning of "multi-task" and "Thread" for PHP programming as clearly as possible.
Types of concurrency
First, let alone a few examples that are irrelevant to the topic. The relationship between PHP and multitasking or concurrency is very complex. At a high level, PHP often involves multi-tasking: using standard server-side PHP installation in a multi-task manner-for example, as an Apache module. In other words, several clients-Web browsers-can simultaneously request pages interpreted by the same PHP, and the Web server will return almost all these pages at the same time.
A Web page does not affect the sending of other Web pages, although it may slightly affect each other due to limited resources such as server memory or network bandwidth. In this way, the PHP-based solution may be suitable for implementing the concurrent system-level requirements. In terms of implementation, PHP allows its Web server to manage for concurrency.
In recent years, client concurrency under Ajax has become the focus of developers' attention. Although the meaning of Ajax has become very vague, one aspect of Ajax is that the browser displays the ability to execute computing and retain responses to user operations such as selecting menu items. This is actually a type of multitasking. PHP-encoded Ajax is like this-but does not involve any specific PHP; Ajax frameworks for other languages are operated in exactly the same way.
The third concurrent instance that only roughly involves PHP is PHP/TK. PHP/TK is an extension of PHP and is used to provide portable graphical user interface (GUI) binding for core PHP. PHP/TK allows you to write code in PHP to construct a desktop GUI application. The event-based feature simulates a concurrency mode that is easier to master and has fewer errors than threads. In addition, concurrency is a secondary technology that "inherits" from, rather than the basic functions of PHP.
The experiment of adding thread support to PHP itself has been done many times. As far as I know, none of them are successful. However, Ajax framework and PHP/TK event-oriented implementation indicate that the event may better reflect PHP concurrency than the thread. PHP V5 proves that this is true.
PHP V5 will provide stream_select ()
With standard PHP V4 and earlier versions, you must perform all the work of the PHP application in sequence. For example, if the program needs to search for the price of the product on two commercial sites, request the price of the first site, wait until the response arrives, then request the price of the second site, and then wait again.
What if the program requests to complete several tasks at the same time? In general, the program will be completed within a period of time, during which it will be processed continuously.
Example 1
The new stream_select Function and Its assistants make this possible. Consider the following example.
Listing 1. Request multiple HTTP pages at the same time
<? Php
Echo "Program starts at". date (h: I: s ).".";
$ Timeout = 10;
$ Result = array ();
$ Sockets = array ();
$ Convenient_read_block = 8192;
/* Issue all requests simultaneously; theres no blocking .*/
$ Delay = 15;
$ Id = 0;
While ($ delay> 0 ){
$ S = stream_socket_client ("phaseit.net: 80", $ errno,
$ Errstr, $ timeout,
STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT );
If ($ s ){
$ Sockets [$ id ++] = $ s;
$ Http_message = "GET/demonstration/delay? Delay = ".
$ Delay. "HTTP/1.0 Host: phaseit.net ";
Fwrite ($ s, $ http_message );
} Else {
Echo "Stream". $ id. "failed to open correctly .";
}
$ Delay-= 3;
}
While (count ($ sockets )){
$ Read = $ sockets;
Stream_select ($ read, $ w = null, $ e = null, $ timeout );
If (count ($ read )){
/* Stream_select generally shuffles $ read, so we need
Compute from which socket (s) were reading .*/
Foreach ($ read as $ r ){
$ Id = array_search ($ r, $ sockets );
$ Data = fread ($ r, $ convenient_read_block );
/* A socket is readable either because it has
Data to read, OR because its at EOF .*/
If (strlen ($ data) = 0 ){
Echo "Stream". $ id. "closes at". date (h: I: s ).".";
Fclose ($ r );
Unset ($ sockets [$ id]);
} Else {
$ Result [$ id]. = $ data;
}
}
} Else {
/* A time-out means that * all * streams have failed
To receive a response .*/
Echo "Time-out! ";
Break;
}
}
?>
If you run this list, you will see the following output.
Listing 2. Typical output from the program in Listing 1
Program starts at 02:38:50.
Stream 4 closes at 02:38:53.
Stream 3 closes at 02:38:56.
Stream 2 closes at 02:38:59.
Stream 1 closes at 02:39:02.
Stream 0 closes at 02:39:05.
Understanding how this works is crucial. At a higher level, the first program will send several HTTP requests and receive the pages that the Web server sends to it. Although production applications are likely to find the addresses of several Web servers, such as google.com, yahoo.com, and ask.com, all of their requests will be sent to the Enterprise Server in Phaseit.net., only to reduce complexity.
The Web page request returns results after the latency (variable), as shown below. If the program sends requests in order, it takes about 15 + 12 + 9 + 6 + 3 (45) seconds to complete. As shown in Listing 2, it actually takes 15 seconds to complete. Performance increased by three times.
This may be caused by the new stream_select function of PHP V5. Requests are initiated in a conventional way, the method is to open several stream_socket_client and correspond to the http://phaseit.net/demonstration/delay? Delay = $ DELAY writes GET to each stream_socket_client. If you request this URL through a browser, after a few seconds, you will see:
Starting at Thu Apr 12 15:05:01 UTC 2007.
Stopping at Thu Apr 12 15:05:05 UTC 2007.
4 second delay.
The latency server is implemented as CGI as follows:
Listing 3. latency server implementation
#! /Bin/sh
Echo "Content-type: text/html
<HTML> <HEAD> </HEAD> <BODY>"
Echo "Starting at 'date '."
RR = 'echo $ REQUEST_URI | sed-e s /.*? //'
DELAY = 'echo $ RR | sed-e s/delay = //'
Sleep $ DELAY
Echo "<br> Stopping at 'date '."
Echo "<br> $ DELAY second delay. </body>
Although the special implementation of listing 3 is specific to UNIX ?, But almost all implementations in this article will be well applied to Windows? (Especially for Versions later than Windows 98) or UNIX installation of PHP. In particular, listing 1 can be hosted on any operating system. Therefore, Linux? And Mac OS X are both UNIX variants, so all the code here can be run in either of them.
Send requests to the delayed server in the following order.
List 4. Process startup sequence
Delay = 15
Delay = 12
Delay = 9
Delay = 6
Delay = 3
Stream_select is used to receive results as quickly as possible. In this case, the execution order is the opposite of the order in which the results are sent. 3 seconds later, the first page is ready for reading. This part of the program also conforms to the conventional PHP-in this example, use fread. Just like in other PHP programs, reading can be done well through fgets.
The processing will continue in the same way. The program stops in stream_select until the data is ready. The important thing is that the program will start to read data as long as any connection has data, regardless of the order. This is a method by which a program processes multiple tasks or concurrently results from multiple requests.
Note that this does not cause any burden on the host CPU. We often encounter such network connection programs that use fread in the while by rapidly increasing the CPU usage to 100%. This is not the case here, because stream_select has the attributes required for immediate response (as long as there is any read information ), however, it will generate negligible CPU load during the wait time between read operations.
Required knowledge about stream_select ()
Such event-based programming is not the most basic. Although Listing 1 is simplified to containing only the most basic elements, any encoding that involves callback or coordination as a necessary element of a multitasking application is more unfamiliar than a simple program order. In this case, most of the challenges are concentrated on the $ read array. Note that it is a reference; stream_select returns important information by changing the content of $ read. Just as pointers are the biggest stumbling block to C, referencing seems to be the most tricky part of PHP.
You can use this technology to send requests to any external Web site, so that your program will receive all results as soon as possible without waiting for other requests. In fact, this technology will correctly process all TCP/IP connections, not just the connections on the Web port 80. Therefore, you can manage LDAP retrieval, SMTP transmission, and SOAP requests in general.
But that's not all. PHP V5 manages various connections such as "streams", not just simple sockets. The PHP Client URL library (CURL) supports HTTPS certificates, FTP uploads, and cookies. (CURL allows PHP applications to connect to the server using various protocols ). Since CURL provides a stream interface, the connection is transparent from the program perspective. The next section will show how stream_select transfers local computing.
Pay attention to stream_select. It is still working on documentation, because even the latest PHP books are not related to it. Available on the Web