Does PHP Have Threading

Does PHP have threading?

There is nothing available that I'm aware of. The next best thing would be to simply have one script execute another via CLI, but that's a bit rudimentary. Depending on what you are trying to do and how complex it is, this may or may not be an option.

Why is not a good idea to use multithreading in php?

Does forking create a Thread ?

When we fork a process, the process space, that is to say the region of memory where the libraries and code the process requires to execute reside, is duplicated, the distinct but related processes then continue to execute at the will of the operating systems scheduler in different regions of memory.

What is the difference between a Forked Process and a Thread ?

When we create a Thread we are telling the operating system that we want another unit of execution that can operate in the same region of memory as the Process that created it.

How different operating systems actually implement threads and processes is beyond the scope of this answer, and is unimportant.

Why is Forking a bad idea at the frontend ?

When you copy the whole address space, you duplicate the region of memory that the webserver is operating in too, this can obviously cause havoc for your operating system.

Why is Threading a bad idea at the frontend ?

If a client script instructs the operating system to create 8 threads in direct response to a web request, and 100 clients simultaneously request the script, you will be instructing your operating system to execute 800 threads concurrently.

CPUs and operating systems would need to look very very different to make that a good idea!

Where is Threading a good idea?

Multi-threaded software, and extremely capable hardware, is ubiquitous; computing would not be what it is without it.

In the context of Web infrastructure, mysql and other database servers are multi-threaded, indeed Apache can deploy PHP in a multi-threaded infrastructure, though I wouldn't recommend it.

When we look at how enterprising applications like mysql actually provide their extremely complex services, we can see that their process (and therefore threads) are completely isolated from the infrastructure of your web application.

This is how we use Threads in languages that support them; we design systems whose means of providing their services is via some sane form of IPC, we isolate our complex infrastructure, completely, from that which should be simple: our web applications.

Is PHP really suitable for Threads ?

The memory model for PHP is shared nothing: this means that each interpreter context, in the sense of the structures and memory PHP requires to operate, is isolated from any other context.

This always has to be true for PHP to work as intended; an implementation of threading for PHP that was ignorant of the way PHP worked simply would not function.

pthreads goes to great lengths to ensure the memory model is not broken, every Thread does indeed not share memory directly with any other Thread.

Are Threads really suitable for me ?

Firstly, seriously think about the following questions:

  • Is Threading really required ?
  • What other ways can you find to achieve whatever it is you are setting out to do ?

Multi-threaded software is complex by nature; something being complicated is no kind of excuse for avoiding it, in my opinion.

But be aware that multi-threaded software is fundamentally different to your average PHP application, you have to think about things you have never had to think about before, be aware of things that didn't matter before you started your first Thread.

You should not guess at what these things are, you should seek to educate yourself in the subject as thoroughly as possible, and even be prepared to fail, and persevere.

The complexity of anything decreases as your knowledge increases, that's how learning works, here is where it begins:

https://gist.github.com/krakjoe/6437782

It continues in the manual, in the many examples distributed with pthreads, in stackoverflow searches and questions, and results in glory, in my opinion.

Running the same script at the same time and PHP's single-threaded status

The single threaded nature of PHP means that PHP doesn't have any built-in support for spawning new threads during script execution.

However, this doesn't mean that you can't have two executions of the same script simultanously.

In the most common setup, your website is served by Apache HTTPD. When an HTTP request for a particular script comes in (e.g. /news.php, Apache executes the script and returns the result. While the script itself cannot launch new threads, Apache itself happily forks whole new processes to service multiple HTTP requests simultanously.

Update

Please see Joe Watkins answer. It appears that PHP indeed does have support for creating threads during execution. However, this doesn't change that fact that you can have simultanous executions of the same script.

How should a PHP thread store its data?

It seems to me that the only way for a thread to store its data properly is to create a new Threaded object and send it to the thread.

Yes, that is one way to do it.

Is it possible to have the thread create its own storage objects when it wants?

Yes, but only if you manipulate it within that thread (or any child threads it may spawn).

One of the fundamental things to understand when using threads in PHP is that objects of a Threaded class are tied to the context in which they are created. This means that if you create a Threaded object in the main thread, pass this object into a spawned child thread, and then join that spawned child thread, then you may continue to use that Threaded object as normal.

Example 1 (constructor injection):

<?php

$store = new Threaded(); // created in the main thread

$thread = new class($store) extends Thread {
public $store;

public function __construct(Threaded $store)
{
$this->store = $store;
}

public function run()
{
$this->store[] = 1;
$this->store[] = 2;
}
};

$thread->start() && $thread->join();

print_r($store); // continue using it in the main thread

This will output:

Threaded Object
(
[0] => 1
[1] => 2
)

In the example above, we could also have created the Threaded object inside of the constructor, and then performed a var_dump($thread->store); at the end of the script. This works because the Threaded object is still being created in the outermost scope in which it is needed, and thus it is not tied to the scope of any child threads that may have already been destroyed. (The only part of a Thread in PHP that is executed in a separate thread is the Thread::run method.)

Similar to the above example, we could also have used setter injection. (Though, again, just so long as the setter is being called by the thread in the outer most scope in which the Threaded object will be used.)

The problem that many developers who are new to threading in PHP seem to encounter, is when they create a Threaded object from inside of a new thread, and then expect to be able to use that Threaded object when they have joined that same thread.

Example:

<?php

$thread = new class() extends Thread {
public $store;

public function run()
{
$this->store = new Threaded(); // created inside of the child thread
$this->store[] = 1;
$this->store[] = 2;
}
};

$thread->start() && $thread->join();

print_r($thread->store); // attempt to use it in the outer context (the main thread)

This will output:

RuntimeException: pthreads detected an attempt to connect to an object which has already been destroyed in %s:%d

This is because the Threaded object in $thread->store has been destroyed when joining the spawned child thread. This problem can be far more subtle, too. For example, creating new arrays inside of Threaded objects will automatically cast them to Volatile objects (which are also Threaded objects).

This means that the following example will not work either:

<?php

$thread = new class() extends Thread {
public $store;

public function run()
{
$this->store = [];
$this->store[] = 1;
$this->store[] = 2;
}
};

$thread->start() && $thread->join();

print_r($thread->store);

Output:

RuntimeException: pthreads detected an attempt to connect to an object which has already been destroyed in %s:%d

To come back to your example code, what you're doing is absolutely fine, but only so long as you do not attempt to use $this->someData outside of that child thread.

Multithreading in PHP

As has been pointed out, php doesn't support multi threading. However, and as tomaszsobczak mentioned, there is a library which will let you create "threads" and leave them running, and reconnect to them through other scripts to check their status and so on, called "Gearman".

From the project homepage: "Gearman provides a generic application framework to farm out work to other machines or processes that are better suited to do the work. It allows you to do work in parallel, to load balance processing, and to call functions between languages. It can be used in a variety of applications, from high-availability web sites to the transport of database replication events. In other words, it is the nervous system for how distributed processing communicates."

Rasmus' blog has a great write up about it here:
playing with gearman and for your case, it might just be the solution, although I've not read any in depth test cases... Would be interested to know though, so if you end up using this, please report back!

Multi Threading / Multi Tasking in PHP

PHP has had a threading model for a very long time, since the first release of PHP4, May 22nd 2000.

Threading at the frontend

Creating user threads at the frontend of a web application doesn't make any sense; it is extremely difficult to scale. The thread per client model that the Apache Worker MPM binary and mod_php employ is not really something you want to use to serve your websites, certainly if you are using it, you do not want to create additional threads in direct response to any web requests.

Why are threads at the frontend a bad idea ?

You may often hear developers say threads at the frontend do not make sense, without providing the rationale for such an assertion. When you learn to think about systems in the required way the problem becomes obvious:

If a client script creates 8 threads in direct response to a web request, and 100 clients request the script simultaneously, you are requesting that your hardware execute 800 threads concurrently.

CPU's would have to look and work very very differently indeed to make that a good idea

What can we do about it ?

Enterprising solutions might well have a PHP website facing the public, but the actual brains of the system are written in languages that have good support for those things you require to build enterprising solutions such as Java, C#, C++ or whatever the language-of-the-day is.

You should use pthreads in the same way; by designing systems whose component parts are separated from one another, only connected by well designed, high performance (RPC) API's, such that the complexity inherent in designing a multi-threaded architecture is isolated completely from your public facing websites, and the simple, scalable setup that such a website will require.

U can now haz codes

Let's start at the beginning with Hello World:

<?php
class My extends Thread {
public function run() {
printf("Hello World\n");
}
}

/* create a new Thread */
$my = new My();

/* start the Thread */
$my->start();

/* do not allow PHP to manage the shutdown of your Threads */
/* if a variable goes out of scope in PHP it is destroyed */
/* joining explicitly ensures integrity of the data contained in an objects */
/* members while other contexts may be accessing them */
$my->join();
?>

Boring, but I hope you read it ;)

So in a real system, you don't really want to be creating threads so explicitly, you surely want to just submit tasks to some executor service, all of the complex systems, in the sense of their multi-tasking requirements, I have ever seen use such things ...

<?php
class My extends Threaded {
public function run() {
printf("Hello World from %s#%lu\n",
__CLASS__, Thread::getCurrentThreadId());
}
}

/* create a Pool of four threads */
/* threads in a pool are created when required */
$pool = new Pool(4);

/* submit a few tasks to the pool */
$tasks = 100;
while ($tasks--) {
$pool->submit(new My());
}

/* shutting down the pool is tantamount to joining all workers */
/* remember what I said about joining ? */
$pool->shutdown();
?>

I have given you very brief explanations of complicated things, you should endeavor to read all you can:

  • https://gist.github.com/krakjoe/6437782
  • https://gist.github.com/krakjoe/9384409
  • http://php.net/pthreads

Many examples can be found here: https://github.com/krakjoe/pthreads/tree/master/examples

Disclaimer: There's nothing really wrong with a server architecture that uses threading, but the moment you start to create additional threads, you restrict it's scalability and ability to perform as it was designed, I can imagine well designed architectures that do have the ability to thread at the frontend, but it is not an easy thing to aim for. Additionally, threading is not the only thing in the toolbox when it comes to high performance web targeted applications; research all your options.



Related Topics



Leave a reply



Submit