In my previous post, I mentioned that I had actually 4 implementations proposal and I commented two of them, which were within the drafted requirements but had an issue with fairness: in both cases, one could bypass the thread pool queue altogether.
Let’s turn our attention to the other two, which are interesting because they share a common issue while having radically different approach.
C#, very short one
| using System; | |
| using System.Threading.Tasks; | |
| namespace Seq | |
| { | |
| public class Sequencer | |
| { | |
| private readonly object _lock = new object(); | |
| private Task _task = Task.FromResult(0); | |
| public void Dispatch(Action action) | |
| { | |
| lock (_lock) | |
| { | |
| _task = _task.ContinueWith(_ => action()); | |
| } | |
| } | |
| } | |
| } |
Java, long implementation
Clearly, the .Net version benefits from the TPL features. That being said, they are actually very close as they share the same algorithm: ordering is secured by creating a private queue, and non concurrency is ensured by making sure at most one task is enqueued or executing in the .net threadpool.
Contract is fulfilled, albeit with a steep price in terms of performance, or more precisely latency. As a task is actually dispatched only after the previous one have been executed, there is a minimum delay between two tasks. So, once again there is a fairness issue. It is obvious that non sequenced tasks would be executed faster than sequenced ones.
Continue reading “The Sequencer (part 2.2)”
