Improved Thread Simulation Class for PHP

Threads. Most PHP scripts do just fine without them. However, when you venture into the domain of complex and numerous database operations, or when you need to deal with datasources of high latency (to put it plainly, HTTP downloads), the multithreading concept starts to look more attractive.

Threading support in PHP is so-so, and the pcntl extension doesn’t work on Windows. Since I’m too lazy to boot up Linux just for the sake of PHP development, I once again went looking for ways to simulate threads (I’ve written about this before).

I created two classes that use asynchronous HTTP POST requests to simulate multithreading (inspired by this class). The Thread simulates a single thread of execution, whereas ThreadManager is an utility class that makes handling multiple threads easier. The script is a bit too long to post here, so …

Download It

thread.zip (3 KB)
Check the examples below for how to use the classes.

Usage Examples

Here you’ll find a few examples of how to use the two classes. You can also take a look inside thread.php for additional info - most class methods contain explanatory comments.

The next code block is common for all examples. In it I include the thread.php file to get access to the classes, and define the test() function which I will use as the example thread function. test($s) simply sleeps for $s seconds and returns a message telling how long it slept.

include_once("includes/thread.php");
function test($s){
	sleep($s);
	return $s." seconds have passed.";
}

Using the Thread class
This example will create two simulated threads and execute them simultaneously. Note that this isn’t the way I’d do it, as handling multiple threads this way is a hassle. However, it shows the basic functions of the class.

$program_start_time = microtime(true);
 
//Create to thread
$thread1 = new Thread;
/*Set the thread function to execute, and it's arguments. Every 
 argument should be passed as an element of the array. The thread 
 function receives the arguments normally.*/
$thread1->setFunc('test', array(3));
//Start the thread
$thread1->start();
 
$thread2 = new Thread;
$thread2->setFunc('test', array(5));
$thread2->start();
 
//Wait while the threads are running
while (!$thread1->finished || !$thread2->finished){
	$thread1->query(); 
	$thread2->query();
/* query($seconds, $useconds) waits for a specified time for the thread 
and processes it's output (if available), filling the Thread::response and 
Thread::result fields. Returns TRUE if the thread is still running, 
FALSE otherwise.*/
}
 
//Output the results
echo "Thread1 : ", $thread1->result,"<br>\n";
echo "Thread2 : ", $thread2->result,"<br>\n";
 
echo "Total execution time : ".(microtime(true)-$program_start_time)." seconds<br />";

You should get output similar to this :

Thread1 : 3 seconds have passed.
Thread2 : 5 seconds have passed.
Total execution time : 5.01491904259 seconds

Note that you can’t pass resource handles to the thread function. Only variables that can be handled by var_export will work.

Using the ThreadManager class
This is functionally equivalent to the previous example, but more elegant.

$program_start_time = microtime(true);
 
//Create a ThreadManager instance with default settings
$manager = new ThreadManager;
 
//Create and start two threads.
$manager->create_thread('test', array(3));
$manager->create_thread('test', array(5));
 
/* Wait until all threads are finished. ThreadManager::query() 
   processes all threads and returns the number of threads that
   are still executing. Check class definition for details.*/
while ($manager->query());
 
//Output the results
foreach ($manager->finished_threads as $id => $thread){
	echo "Thread '$id' : ", $thread->result,"<br>\n";
}
echo "Total execution time : ".(microtime(true)-$program_start_time)." seconds<br />";

The expected output is something like this :

Thread '_thread_1' : 3 seconds have passed.
Thread '_thread_2' : 5 seconds have passed.
Total execution time : 5.01980900764 seconds

ThreadManager also has a handy pop_finished_thread() function which returns a finished thread and removes it from managers internal lists.

Final Notes

I’m using the class in my DA recommender project and it seems to be working nicely so far. If you have any questions, feel free to comment ;)

Related posts :

4 Responses to “Improved Thread Simulation Class for PHP”

  1. 1
    Chris Says:

    I have tried the class on two different server environments both give me an error 404!

    Is there anything I need to check?

  2. 2
    Chris Says:

    @Chris - I take that back- it now gives me a decoding error. Will keep playing.

  3. 3
    Chris Says:

    @Chris - Got the example code to work. However when running it through my code I get a decoding error :o

  4. 4
    White Shadow Says:

    @Chris - It has been quite a while since I wrote/used this class, so I don’t have any ideas off-hand. Anyway, I’d start looking at the “The response was :” part to see why the response can’t be decoded, and work from there.

Leave a Reply