Single Writer Principle: Why Allowing Only a Single Writer to Do the Writing Can Speed Up Your Application
Every day, you are using this approach without even knowing it.
Forget about mutexes and fancy synchronization techniques for now. Let's ask ourselves a very basic question.
What if, instead of coordinating many writers writing in the same book, we allow just one writer to write there?
What would be its advantages? What would be its disadvantages?
This basic concept forms the basis of many efficient and scalable applications that you will learn about later in the chapter. It is known as the Single Writer Principle.
In the Case of Race Between Several Authors
Letβs picture an account that has 100 dollars.
Two commands almost simultaneously enter the system:
- add 50
- subtract 20
Both threads would probably read 100 as the initial amount, compute, and overwrite one another's calculation results.
Depending on circumstances, the final balance may not be correct.
Here we come across the typical race condition problem.
What is the very first solution that occurs?
Indeed! β use a lock.
That works.
But not for free, of course.
The Costs of Locking
Many software developers believe that a lock is just a tiny cost - a few nanoseconds.
In fact, the indirect costs may be significantly higher:
- The threads wait for a lock.
- Context switching is done by the OS.
- CPU cores constantly invalidate cache lines of other cores (cache invalidation).
- Deadlocks can happen more often.
- The code gets really hard to understand and that's precisely what drives developers nuts.
As the number of threads increases, performance does not necessarily increase.
Quite often, it drops.
A More Sophisticated Approach - Keep Things Simple
Allow Only One Thread to Write
The Single Writer approach sounds pretty simple.
Instead of letting every thread to update the shared state directly (note how important the term state becomes here) all threads just push their updates into the queue.
And a single thread takes care of the queue processing requests one by one.
No matter what, there is always just one writer that changes the shared state at the time.
Since there is no concurrent writes:
- No race conditions anymore.
- Locks are usually redundant.
- The code becomes way more understandable.
Why can a Single Thread be faster than Multiple Threads?
At first glance, it sounds strange.
How can a single thread be faster than multiple threads?
But everything is very simple.
If there is always a lock for which multiple threads are waiting, then all threads spend their time not working but competing among themselves for the right to take the lock.
On the other hand, a Single Writer does not wait for locks and does not coordinate with other writers while processing incoming requests.
CPU also gets:
- Sequential access to memory
- Improved Cache Locality
- No Cache Line bouncing due to concurrent write operations
That's why, in a lot of highly performant systems, reduction of contention is more beneficial than increasing the number of threads.
When do you see this pattern?
The Single Writer pattern is not only theoretical.
There are many technologies that use this pattern.
LMAX Disruptor
LMAX Disruptor is built in such a way that each piece of the state is written by exactly one writer, thus achieving the speed of millions operations per second.
Redis
Probably the most familiar example.
Redis executes commands through a single event loop.
Because only one thread modifies its internal data structures, Redis doesn't need locks for most of its core operations.
Actor Model (Akka, Orleans)
Each actor owns its own state.
Messages are processed sequentially, so only the actor itself can modify its internal state.
Should You Always Use Single Writer?
Of course not!
In software engineering, rarely anything works all the time, except this statement itself :)
If operations are fully independent and do not access shared state, running in parallel is preferable.
But when multiple threads continuously compete to modify the shared state, the use of the Single Writer pattern can simplify the code and make it perform better.
Note, that this pattern does not exclude the use of parallelism at all.
Actually, the pattern shifts the point of parallelism to the place it makes sense.
Expensive calculations can still be performed in parallel.
But the write to the shared state is done by only one thread.
Conclusion
So, the Single Writer Principle can be formulated very briefly:
Each shared state should have only one writer.
This simple idea gets rid of most challenging aspects of concurrent programming.
- No more race conditions.
- Locks become unnecessary.
- Code becomes easier to understand.
- Behavior becomes deterministic.
- Throughput is usually improved in cases of contention.
That's why the high-performance system rarely starts with the addition of more threads.
Instead, the following question is asked first:
Can we make the number of writers equal to one?


Top comments (0)