Boosting Laravel Performance using Laravel's Concurrency Facade

LaravelBackend Development

When building a web application in Laravel, especially a dashboard, it’s common to display metrics like the count of users, orders, and products. If these statistics are fetched sequentially, first the user count, then the order count, and then the product count, each request has to wait for the previous one to finish, resulting in a slower dashboard load time.

For a dashboard, data like user count, order count, and product count are fetched using separate database queries.

In traditional setups, these queries execute one after another, increasing the total response time and slowing down the user experience, especially if the queries are complex or need to access large data sets.

Consider the following logic for a dashboard:

  • Call the database to get the user count.
  • Wait for that to finish, then call the database to get the order count.
  • Then again wait for that to finish, then call the database to get the product count.
  • Return all counts and render the dashboard.

If each query takes 200 ms, your dashboard might take 600 ms just for these three stats, before any additional work is done.

Impact on Performance

Fetching metrics in sequence is simple, but it's inefficient for independent stats. Users often experience noticeable delays if the dashboard has multiple statistics or if external services are called for each metric.

Since these counts don't depend on each other, Laravel concurrency lets us fetch them all at once instead of one by one, which makes the dashboard much faster.

Running Tasks Sequentially vs Concurrently

Let's start with a simple example to show the difference between running code one after another and running it at the same time.

Sequential Execution

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    $start = microtime(true); // Record start time

    sleep3(); // This takes 3 seconds
    sleep5(); // This takes 5 seconds

    $end = microtime(true); // Record end time
    dd('Task completed in seconds: ' . ($end - $start));
});

function sleep3() {
    sleep(3);
}

function sleep5() {
    sleep(5);
}

In this example, there are two functions: sleep3 takes 3 seconds to finish, and sleep5 takes 5 seconds to finish. Because one runs after the other, the total time taken is 8 seconds.

image-without-concurrency

Concurrent Execution (with Laravel Concurrency)


Now, let's use Laravel's Concurrency facade to run both functions at the same time:

<?php

use Illuminate\Support\Facades\Concurrency;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    $start = microtime(true); // Record start time

    [$sleep3, $sleep5] = Concurrency::run([
        fn() => sleep3(),
        fn() => sleep5(),
    ]);

    $end = microtime(true); // Record end time
    dd('Task completed in seconds: ' . ($end - $start));
});

function sleep3() {
    sleep(3);
}

function sleep5() {
    sleep(5);
}
image-with-laravel-concurrency

Now, both functions start at the same time. The total time taken is just 5 seconds, which is the time needed for the longer function to finish. By running tasks together, Laravel helps your dashboard load much faster and makes better use of resources

By using Laravel's concurrency features, independent tasks, like fetching multiple counts or making several API calls, can run at the same time instead of one after another. This approach makes dashboards and other parts of your app load much faster, because only the longest task sets the total wait time, not the sum of all tasks. Laravel makes it easy to apply this pattern, helping to optimize performance and improve user experience.

Thank you for reading the article.