Programster's Blog

Tutorials focusing on Linux, programming, and open-source

A Really Basic Swoole Threading Example

The first thing I wanted to try out when starting with Swoole, is some basic threading to see what kind of performance increase one could expect.

Related Posts

Single Threaded Example:

Below is a single-threaded example of printing out the prime numbers that exist between a pair of numbers. The functions have been set as variables so that this example and the threaded example are as close as possible.

<?php
$timeStart = microtime(true);

$isPrime = function($n) {
    for ($x=2; $x<$n; $x++)
    {
        if ($n %$x ==0)
        {
            return false;
        }
    }

    return true;
};

$findPrimeNumbers = function($start, $end) use($isPrime){
    for ($i=$start; $i <= $end; $i++)
    {
        if ($isPrime($i))
        {
            print "$i is a prime number" . PHP_EOL;
        }
    }
};

$numThreads = 6;
$start = 10000000;
$end = 10010000;

$findPrimeNumbers($start, $end);

$timeEnd = microtime(true);
$timediff = $timeEnd - $timeStart;
print "That took " . $timediff . " seconds" . PHP_EOL;

Swoole Multithreaded Example:

Below is a multi-threaded example whereby I split the range of numbers into sub-chunks for the threads to loop over and fetch the prime numbers for. Now there isn't one range, but 6 smaller ones.

<?php
$timeStart = microtime(true);

$isPrime = function($n) {
    for ($x=2; $x<$n; $x++)
    {
        if ($n %$x ==0)
        {
            return false;
        }
    }

    return true;
};

$findPrimeNumbers = function($start, $end) use($isPrime){
    for ($i=$start; $i <= $end; $i++)
    {
        if ($isPrime($i))
        {
            print "$i is a prime number" . PHP_EOL;
        }
    }
};

$numThreads = 6;
$start = 10000000;
$end = 10010000;
$range = $end - $start;
$chunkSize = intval($range / $numThreads);

for ($i=0; $i<$numThreads; $i++)
{
    $threadStart = $start + ($i * $chunkSize);
    $threadEnd = $threadStart + $chunkSize;
    print "Allocating thread to $threadStart - $threadEnd" . PHP_EOL;

    $processes[$i] = new \Swoole\Process(function () use ($findPrimeNumbers, $threadStart, $threadEnd) {
        $findPrimeNumbers($threadStart, $threadEnd);
    });

    $processes[$i]->start();
}

for ($i=0; $i<$numThreads; $i++)
{
    \Swoole\Process::wait(true);
}

$timeEnd = microtime(true);
$timediff = $timeEnd - $timeStart;
print "That took " . $timediff . " seconds" . PHP_EOL;

Results

Below are the results comparing a the single-threaded performance against running on all 6 cores of my Ryzen 3500x.

The single-threaded example took 12.42 seconds to complete, whilst the traditional single-threaded logic took 61.08 seconds. This means that spreading the workload over 6 threads made the application go 4.23 times faster. I was a little disappointed that spreading over 6 cores didn't get me to at least 5 times faster, but one has to take into account that not only are there extra overheads, modern CPUs have "turbo boost" when only one thread is really working hard, which I believe was probably largely at play here, as the server was doing nothing else on the other cores.

Last updated: 28th June 2021
First published: 26th June 2021

This blog is created by Stuart Page

I'm a freelance web developer and technology consultant based in Surrey, UK, with over 10 years experience in web development, DevOps, Linux Administration, and IT solutions.

Need support with your infrastructure or web services?

Get in touch