Understanding Concurrency in PHP with Laravel: A Beginner's Guide

WhoAmI => notes.sohag.pro/author
Search for a command to run...

WhoAmI => notes.sohag.pro/author
No comments yet. Be the first to comment.
Unlocking Productivity: My Favorite Daily Apps In today’s fast-paced world, staying organized and productive can feel like a daunting task. With countless distractions at our fingertips, having the right tools can make all the difference. As someone ...
I had a solid list of reasons my life wasn't moving faster, until a grainy old lecture pointed out the one name missing from it

The finale isn't a victory lap. It's the story of the control I shipped that did nothing, the footgun still sitting in my demo, and the handful of things I'd keep exactly as they are.

How do you hold a large payment for a second pair of eyes without ever letting the unapproved money touch a balance, and how do you stream that decision to the outside world without standing up a broker?

How do you show the total under a parent account when the whole system refuses to store a balance? A recursive query, a trigger that refuses to draw a circle, and a rule about what actually has to sum to zero.

Every time I wanted to change an FX rate I had to edit a file on the server and restart the app. So I moved rates and markup into a live admin API, and then audited it hard enough to find the bug that quietly undid the whole thing.

Concurrency is an important concept in software development, especially when building scalable and high-performance applications. In simple terms, concurrency allows multiple tasks to run at the same time or in overlapping periods. While PHP traditionally works in a single-threaded environment, tools and techniques like threads, synchronization, thread pools, asynchronous processing, locks, semaphores, deadlocks, and race conditions can make it possible to execute tasks concurrently. In this post, we’ll dive into these concepts and explore how they can be applied to PHP, specifically with Laravel.
Concurrency refers to the ability of an application to handle multiple tasks or processes at the same time, or in overlapping periods. It allows applications to perform complex operations without waiting for one task to complete before starting another. It’s similar to how we manage multiple things in our daily lives.
Imagine you're in a kitchen cooking dinner. You have multiple tasks at hand: boiling water, chopping vegetables, and frying an egg. Instead of waiting for one task to finish before starting the next, you work on several tasks simultaneously, using a kitchen timer to keep track of when things need attention. Similarly, in software, concurrency allows the application to handle multiple operations simultaneously or in overlapping time slots.
Threads are lightweight processes that can run independently but share the same resources like memory.
A Thread Pool is a collection of threads that can be reused to perform multiple tasks, which helps to manage resources efficiently.
Think of a thread pool like a team of chefs working together in a kitchen. Instead of hiring a new chef for every dish (which would take time), you have a set number of chefs (threads) that rotate between tasks, efficiently handling many dishes (tasks) without wasting resources.
In PHP, you can use ReactPHP to simulate asynchronous threads. Laravel doesn't directly support thread pooling out of the box, but you can achieve similar results using queue workers.
use Illuminate\Support\Facades\Queue;
Queue::push(function ($job) {
// Simulate a task
sleep(5); // Pretend this task takes time
echo "Task Completed!";
});
This code simulates concurrent processing by pushing tasks onto a queue. Laravel processes tasks asynchronously via workers.
Imagine a single shared bathroom in a house with multiple family members. Each family member must wait their turn to use the bathroom to avoid any conflicts or issues.
You can use Laravel’s database transactions or file locks to synchronize access to shared resources.
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
// Perform database operations in sync
DB::table('users')->update(['status' => 'active']);
});
Here, database transactions ensure that only one process can modify the database at a time, preventing conflicts.
If you're waiting for the oven to bake a cake, instead of watching it bake, you could be preparing frosting or setting the table. The task (baking) continues in the background while you do other things.
Laravel's queue system is perfect for asynchronous processing.
use App\Jobs\ProcessImage;
ProcessImage::dispatch($image);
The dispatch method sends the job to the queue, allowing the rest of your application to keep running while the background task is processed.
A Lock is a mechanism to prevent multiple processes from accessing a resource at the same time.
A Semaphore is a more advanced mechanism, allowing a fixed number of threads to access a resource concurrently.
Think of a lock as a key to a locker. Only one person can use the locker at a time, preventing others from accessing it simultaneously.
For file-based locks, Laravel provides cache locks.
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('some-lock', 10); // Lock for 10 seconds
if ($lock->get()) {
// Critical section
// Task performed while holding the lock
$lock->release();
} else {
// Lock not acquired
}
In this case, the lock ensures that only one process can access a shared resource at a time, preventing conflicts.
Deadlock happens when two or more processes are blocked, waiting for each other to release resources.
Race Condition happens when two processes try to modify the same resource at the same time, resulting in unpredictable behavior.
A deadlock in daily life would be if two people are walking towards each other in a hallway, and neither can pass because both are waiting for the other to move first.
A race condition is like two people trying to grab the last piece of pizza at the same time. Whichever grabs it first wins, but the result can change depending on the timing.
For a deadlock, ensure that you’re using proper synchronization mechanisms, like transactions or locks, to avoid circular waiting.
For a race condition, using locks can prevent multiple processes from modifying the same resource simultaneously.
// Preventing a race condition
Cache::lock('unique-resource', 10);
Use queues: Offload time-consuming tasks to a queue to improve performance.
Always handle exceptions: When using asynchronous tasks or locks, ensure proper exception handling in case of failures.
Optimize worker numbers: Ensure that your server resources align with the number of workers you spawn.
Keep tasks small: Each task handled by a queue should be small and focused on a single operation to avoid bottlenecks.
PHP Async Programming with ReactPHP
Laravel Queue System: Delayed Jobs, Failed Jobs
Multithreading in PHP (via pthreads, ReactPHP)
Database Transactions in Laravel
Design Patterns for Concurrency in Software Development
Distributed Systems and Load Balancing
Concurrency is an essential concept in modern software development, and with tools like Laravel’s queue system, synchronization mechanisms, and locks, PHP developers can build scalable applications that can perform multiple tasks efficiently. By understanding concepts like thread pools, asynchronous processing, and race conditions, you can optimize your application for better performance and reliability.
The best way to get better at concurrency in PHP is to practice! Experiment with Laravel queues, implement locks, and tackle concurrency-related issues in your own projects.
Happy coding!