DEV Community

Wisdom Ebong
Wisdom Ebong

Posted on • Edited on

Using Asynchronous Processes in PHP.

For most programs written in PHP, its sole purpose is to execute a simple process consisting of multiple tasks, where the tasks must be executed in sequence such as data processing. We always have to tolerate the stop and wait aspect of synchronous programming. The synchronous style of code execution is referred to as blocking, this implies that tasks will be executed one by one. So what if we want to run tasks without them blocking each other, that means we need to have a non-blocking process? This approach would require applying asynchronous programming approaches in PHP, here tasks will be executed without depending on of each other.

A common approach to achieve a non-blocking execution in PHP is to implement queue processing. Tasks are persisted to a transport system e.g MySQL, Redis, Amazon SQS e.t.c, which is retrieved by a background worker and executed accordingly, thereby not blocking the main process in which it was created. A laravel application provides a queue mechanism that allows tasks in this case called jobs to be deferred for to a later time for processing.

Another approach would be to run all defined tasks in parallel. What we get out of this approach is that a particular task is done it can return control back to the main process immediately with a promise to execute code and notify us about the result later(e.g. callback). One might see little use case for the parallel processing approach; example use case could be performing image processing and making a get request to some external service.

Let’s see the difference between synchronous and asynchronous (parallel) process in PHP using a very simple use case.

Synchronous code

  foreach (range(1, 5) as $i) {
     $output = $i * 2;
     echo $output . "\n";
  }
Enter fullscreen mode Exit fullscreen mode

Asynchronous code

    use Spatie\Async\Pool;

    $pool = Pool::create();

    foreach (range(1, 5) as $i) {
        $pool[] = async(function () use ($i) {
           $output = $i * 2;
           return $output;
        })->then(function (int $output) {
           echo $output . "\n";
        });
    }
    await($pool);
Enter fullscreen mode Exit fullscreen mode

When we execute the first code we will get the output values in this order:

2
4
6
8
10
Enter fullscreen mode Exit fullscreen mode

Retrying the execution, we will get the output in this same sequence above … hence each multiplication operation waits to execute before the next one. Next, running the second code block, let’s see what we get.

6
10
2
8
4
Enter fullscreen mode Exit fullscreen mode

Retrying the execution for the second time:

2
6
4
10
8
Enter fullscreen mode Exit fullscreen mode

One process happens to produce two different results. This exactly is what we get for utilising the asynchronous approach … our little tasks can be executed in a fashion they don’t block each other. Each multiplication task executes independently, some faster than others hence the disorderliness in the output. Also, notice our async function as a then method attached to it, this method is responsible for taking back control and it accepts a callback function as its parameter which can now perform extra operations with the received output.

The folks at Spatie made this nice spatie/async package, which helps in performing tasks in parallel. You can install the package via composer:

composer require spatie/async
Enter fullscreen mode Exit fullscreen mode

The package provides a neat way to interact with the tasks created, that are to be executed in parallel. The Event Listeners on the tasks are described below:

  • Performing another operation when the task is done as the callback is achievable with its then method.
  • Error handling is easier to control when a particular task throws an exception using the catch method.
  • Take for instance a task does not complete its operation, a timeout method allows one to handle such a scenario.

The event listeners are hooked to a task as shown below:

    $pool
        ->add(function () {
            // Task to be performed in a Parallel process
        })
        ->then(function ($output) {
            // On success, `$output` is returned by the process or callable you passed to           the queue.
        })
        ->catch(function ($exception) {
            // When an exception is thrown from within a process, it's caught and passed here.
        })
        ->timeout(function () {
            // Ohh No! A process took too long to finish. Let's do something 
        })
    ;
Enter fullscreen mode Exit fullscreen mode

To learn more about the spatie/async package read this article from one of its contributors here and you can also refer to the GitHub repo.

Top comments (16)

Collapse
 
damlight profile image
Daei_F

This is great. I hope PHP7 finally brings native async, they've made so many advances but async is something so many people really wants from it

Collapse
 
zexias profile image
Matheus Faustino

for async and concurrent code I really like Amp project. It's really good and easy to integrate: amphp.org/

Collapse
 
johnsamuelob profile image
John Samuel Obinna

Awesome Post 😎

Collapse
 
opensaucedeveloper profile image
Afolayan Oluwaseun Raphael

Thank you very much for sharing this✨. Definable learnt a lot as regards async operations.

Collapse
 
arunnabraham profile image
arunnabraham

Async is one of the needy feature inbuilt to PHP. As per Nikita this feature wont come anytime soon. Which is sad. However if you want performance in PHP Asynchronus Programming, defenitly checkout SwoolPHP which has been less noticed over years since its inception. Its features are inspired from NodeJS and Golang. Performance is far better than NodeJS maybe kind of closer to Go.

Instead of library like ReactPHP or AmPHP it is written in C as PHP extension. Yet its feature rich like these librarires.

Checkout their links

swoole.co.uk/

github.com/swoole/swoole-src

swoolebook.com/

Collapse
 
technoexpress profile image
L. Stubbs

How about something actually more native like, and simpler to use, all pure PHP base.

symplely.github.io/coroutine/

Collapse
 
cvar1984 profile image
Bellatrix Lugosi

Hmm, i prefer amp/parallel because it works for both web and console

Collapse
 
efeferrari profile image
franco

I tried the example, but with this result:

Argument 1 passed to await() must be an instance of Spatie\Async\Pool, instance of Spatie\Async\Process\SynchronousProcess given.

Collapse
 
roelofjanelsinga profile image
Roelof Jan Elsinga

I needed to see this post! I've been struggling with this and finally just switched to using Golang. This definitely seems to be something I could have used! Great post! ⚡

Collapse
 
mehdifathi profile image
Mehdi Fathi

I think asynchronous doesn't fitt with Php.may be you can use another language to implement asynchronous as Node.js or Golang. If you want to see deep your job in async PHP is not good for you

Collapse
 
aldora profile image
Aldora

I can't use your second code block which use spatie\async produce different result, it's still 2,4,6,8,10

Collapse
 
aldora profile image
Aldora

Sorry, it turns out to be my homestead enviroment problem