What is multi threading in php?

The hierarchy of the basic classes, which we have just mentioned, is represented in the diagram.

Threaded - It is pthreads basis. It makes it possible to run code in parallel. It provides methods for synchronization and other useful techniques.

Thread - You can create a sub-class of Thread and implement the method run(). This method starts executing a separate thread when you call the start() method. The thread can only be initiated from the process that created the thread. Combining threads can also only be done in this same process.

Worker - Worked threads have a persistent context that can be used by different threads. It is available only while the worker object has references to it and until shutdown() method is called.

In addition to these classes, there is the Pool class.

Pool - a pool is a container of workers that can be used for distribution jobs between Worker objects. Pool is the simplest and most effective way to organize several threads.

There is not much else to be said about the theory. So let's immediately try all this with an example.

It is possible to solve complex problems splitting tasks in multiple threads. I was interested to solve one particular problem that seems to me that is very typical. Let me describe it. There is a pool of tasks that need to be executed as fast as possible.

So let's get started. To do this, create a data provider object of MyDataProvider (Threaded) class. There will be only one object and it is the same for all threads.

/**
 * Provider data flows
 */
class MyDataProvider extends Threaded
{
    /**
     * @var int How many items in our imaginary database
     */
    private $total = 2000000;

    /**
     * @var int How many items were processed
     */
    private $processed = 0;

    /**
     * We go to the next item and return it
     * 
     * @return mixed
     */
    public function getNext()
    {
        if ($this->processed === $this->total) {
            return null;
        }

        $this->processed++;

        return $this->processed;
    }
}

For each task we will use the MyWorker (Worker) class, which will be stored on the parent process.

/**
 * MyWorker here is used to share the provider between instances MyWork.
 */
class MyWorker extends Worker
{
    /**
     * @var MyDataProvider
     */
    private $provider;

    /**
     * @param MyDataProvider $provider
     */
    public function __construct(MyDataProvider $provider)
    {
        $this->provider = $provider;
    }

    /**
     * Called when sending in the Pool
     */
    public function run()
    {
        // In this example, we do not need to do anything here
    }

    /**
     * Returns the provider
     * 
     * @return MyDataProvider
     */
    public function getProvider()
    {
        return $this->provider;
    }
}

The processing of each pool task, lets suppose it is a kind of time consuming operation, is our bottleneck. So we start a multi-threaded task using MyWork (Threaded) class.

/**
 * MyWork is a task that can be executed in parallel
 */
class MyWork extends Threaded
{

    public function run()
    {
        do {
            $value = null;

            $provider = $this->worker->getProvider();

            // Sync obtaining data
            $provider->synchronized( function( $provider ) use (&$value) {
               $value = $provider->getNext();
            }, $provider);

            if ($value === null) {
                continue;
            }

            // A certain consuming operation
            $count = 100;
            for ($j = 1; $j <= $count; $j++) {
                sqrt($j+$value) + sin($value/$j) + cos($value);
            }
        }
        while ($value !== null);
    }

}

Note that to pick up the data from the service provider you need to use the synchronized() function. Otherwise, there is the possibility that the data be processed more than one time, or you may miss some data.

Now we make it all work using the Pool object.

require_once 'MyWorker.php';
require_once 'MyWork.php';
require_once 'MyDataProvider.php';

$threads = 8;

// Create provider. This service may for example read some data
// from a file or from the database
$provider = new MyDataProvider();

// Create a pool of workers
$pool = new Pool($threads, 'MyWorker', [$provider]);

$start = microtime(true);

// In this case flows are balanced. 
// Therefore, there is good to create as many threads as processes in our pool.
$workers = $threads;
for ($i = 0; $i < $workers; $i++) {
    $pool->submit(new MyWork());
}

$pool->shutdown();

printf("Done for %.2f seconds" . PHP_EOL, microtime(true) - $start);

This is a rather elegant solution in my opinion.

That's all! Well, that is almost everything you need to do.

Actually, there is something that might disappoint the inquisitive reader. This does not work on a standard PHP, compiled with the default options. To use pthreads multi-threading support it is necessary to compile PHP with the ZTS (Zend Thread Safety) option.

PHP Settings

The documentation says that PHP must be compiled with the option --enable-maintainer-zts. I have not tried to compile itself. Instead found a PHP package for Debian that was built with that option. You can install it like this.

sudo add-apt-repository ppa:ondrej/php-zts
sudo apt update
sudo apt-get install php7.0-zts php7.0-zts-dev

So I have the old PHP, which runs from the console in the usual way, using the php command. Accordingly, the Web server uses it the same. And there is another PHP, which can be run from the console through php7.0-zts.

You can then add the the pthreads extension.

git clone https://github.com/krakjoe/pthreads.git
./configure
make -j8
sudo make install
echo "extension=pthreads.so" > /etc/pthreads.ini
sudo cp pthreads.ini /etc/php/7.0-zts/cli/conf.d/pthreads.ini

Now that is all. Well almost everything. Imagine that you have written multi-threaded code, and PHP on the evnvironment of a colleague is not set up properly. This may cause confusion, doesn't it? But there is a solution.

Polyfill

Here again thank Joe Watkins for pthreads-polyfill package. The essence of the decision is as follows: this package contains classes that have the same names as in the pthreads extension. They allow you to execute your code, even if you do not have enabled the pthreads extension. Just code is executed in one thread.

For this to work, you simply install this package using composer and nothing else. There is a check whether the extension is installed. If the extension is installed, it uses the extension. Otherwise, the polyfill classes are used so you can start at least one thread.

Analysis

Let's now see whether the processing is really going on as we expect in multiple threads and evaluate the benefit of using this approach.

I will change the value of $threads variable from the above example and see what happens.

Information about the processor on which to run tests

$ lscpu
CPU(s):                8
Threads per core:      2
Cores per socket:      4
Model name:            Intel(R) Core(TM) i7-4700HQ CPU @ 2.40GHz

Let's see chart of the CPU cores. It is all in line with the expectations.

$threads = 1

What is multi threading in php?

$threads = 2

What is multi threading in php?

$threads = 4

What is multi threading in php?

$threads = 8

What is multi threading in php?

And now the most important thing for which all this. Compare the execution time.

$threadsNoteExecution Time, seconds
PHP without ZTS
1 without pthreads, without polyfill 265.05
1 polyfill 298.26
PHP with ZTS
1 without pthreads, without polyfill 37.65
1 68.58
2 26.18
3 16.87
4 12.96
5 12.57
6 12.07
7 11.78
8 11.62

From the first two lines it can be seen that when using polyfill we have lost about 13% of the performance in this example, a relatively linear code.

Furthermore, about PHP with ZTS, do not pay attention to such a big difference in execution time compared to PHP without ZTS (37.65 versus 265.05 seconds). I was not trying to optimize for the most common PHP settings. In the case of PHP without ZTS I have XDebug enabled for example.

As can be seen, by using 2 threads, the program execution speed is approximately 1.5 times higher than in the case of linear code. When using a 4 threads, 3 times.

You can note that even though the processor has 8 cores, run-time program execution almost did not change, if you used a 4 threads. It seems that this is due to the fact that the number of physical cores in my CPU 4. For clarity, depicted as a diagram plate.

What is multi threading in php?

What is multi threading with example?

What is MultiThreading? Multithreading enables us to run multiple threads concurrently. For example in a web browser, we can have one thread which handles the user interface, and in parallel we can have another thread which fetches the data to be displayed. So multithreading improves the responsiveness of a system.

What is multi threading process?

Multithreading is a model of program execution that allows for multiple threads to be created within a process, executing independently but concurrently sharing process resources. Depending on the hardware, threads can run fully parallel if they are distributed to their own CPU core.

What is multi threading and types?

Multithreading is running multiple tasks within a process. It is of two types, namely user level threads and kernel level threads. It is economical, responsive, scalable, efficient, and allows resource sharing. There are three models in multithreading: Many to many model, Many to one model, and one to one model.

Why is PHP not multithreaded?

PHP does not give inbuilt multi-threading functionality, we need to add package/extension “threads” to our PHP. Threaded Objects: A class that is a unit of executable instructions (thread), It is what you want to execute asynchronously. the run method in this class has the ability to execute it as a thread.