PHP developers seem to rarely utilise parallelism. The appeal of the simplicity of synchronous, single-threaded programming certainly is high, but sometimes the usage of a little concurrency can bring some worthwhile performance improvements.
In this article, we will be taking a look at how threading can be achieved in PHP with the pthreads extension. This will require a ZTS (Zend Thread Safety) version of PHP 7.x installed, along with the pthreads v3 installed. (At the time of writing, PHP 7.1 users will need to install from the master branch of the pthreads repo - see this article's section for details on building third-party extensions from source.)
Just as a quick clarification: pthreads v2 targets PHP 5.x and is no longer supported; pthreads v3 targets PHP 7.x and is being actively developed.
A big thank you to Joe Watkins (creator of the pthreads extension) for proofreading and helping to improve my article!
When Not to Use Pthreads
Before we move on, I would first like to clarify when you should not (as well as cannot) use the pthreads extension.
In pthreads v2, the recommendation was that pthreads should not be used in a web server environment (i.e. in an FCGI process). As of pthreads v3, this recommendation has been enforced, so now you simply cannot use it in a web server environment. The two prominent reasons for this are:
- It is not safe to use multiple threads in such an environment (causing IO issues, amongst other problems).
- It does not scale well. For example, let's say you have a PHP script that creates a new thread to handle some work, and that script is executed upon each request. This means that for each request, your application will create one new thread (this is a 1:1 threading model - one thread to one request). If your application is serving 1,000 requests per second, then it is creating 1,000 threads per second! Having this many threads running on a single machine will quickly inundate it, and the problem will only be exacerbated as the request rate increases.
That's why threading is not a good solution in such an environment. If you're looking for threading as a solution to IO-blocking tasks (such as performing HTTP requests), then let me point you in the direction of asynchronous programming, which can be achieved via frameworks such as Amp. SitePoint has released some excellent articles that cover this topic (such as writing asynchronous libraries and Modding Minecraft in PHP), in case you're interested.
With that out of the way, let's jump straight into things!
Handling One-off Tasks
Sometimes, you will want to handle one-off tasks in a multi-threaded way (such as performing some IO-bound task). In such instances, the Thread
class may be used to create a new thread and run some unit of work in that separate thread.
For example:
$task = new class extends Thread {
private $response;
public function run()
{
$content = file_get_contents("http://google.com");
preg_match("~<title>(.+)</title>~", $content, $matches);
$this->response = $matches[1];
}
};
$task->start() && $task->join();
var_dump($task->response); // string(6) "Google"
In the above, the run
method is our unit of work that will be executed inside of the new thread. When invoking Thread::start
, the new thread is spawned and the run
method is invoked. We then join the spawned thread back to the main thread (via Thread::join
), which will block until the separate thread has finished executing. This ensures that the task has finished executing before we attempt to output the result (stored in $task->response
).
Continue reading %Parallel Programming with Pthreads in PHP – the Fundamentals%
by Thomas Punt via SitePoint
No comments:
Post a Comment