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