Simulate Process Time In C#
Can a program run too fast? If you ask me, I say yes. Sometimes you can actually improve the user experience by slowing down your program. Don't believe me? Imagine you are playing a game of chess against a computer opponent. Every move you make takes you at least five seconds to reason out and execute. Now imagine that after making your carefully crafted move, your computer adversary immediately makes a superior move. You start to feel annoyed and exhausted because you never get a break. The computer is kicking your butt without even breaking a sweat.
Image Credit: Tristan Schmurr
If, however, the computer opponent takes a few seconds to make her move, the user feels as if he is challenging his opponent. The user also has some time to relax between turns and thus enjoys the match all the more.
Hopefully I have convinced you that simulating process time is occasionally useful. Now let’s do it!
First Attempt
Say we want an action to take at least five seconds. If the action actually takes six seconds, we don't want to tack on an additional five seconds. If the action only takes two seconds however, we do want to tack on three more seconds so that the user thinks it took us five seconds.
var endTime = DateTime.Now.AddSeconds(5);
PerformAction();
while(DateTime.Now < endTime)
{
Thread.Sleep(100);
}
This will work but we have to repeat the code everywhere we need to simulate process time. We could push the while loop into a function.
var endTime = DateTime.Now.AddSeconds(5);
PerformAction();
SimulateProcessTimeIfNeeded(endTime);
But there is still too much process time simulation code there distracting the reader from the true purpose of the code.
A Better Solution
What we really need is a DRY way to simulate process time that does not distract from the true purpose of the code. Something like this:
using (new MinimumSeconds(5))
{
PerformAction();
}
Isn't that nice? It reads really well and there is no Thread.Sleep(5)
to copy around all over the place. But how does this work? Simple, the using block ensures that the object declared inside the parentheses gets disposed. We just record the time in the constructor for MinimumSeconds
and make sure we don't finish disposing until the requested time span has elapsed.
public class MinimumSeconds : IDisposable
{
private DateTime _EndTime;
public MinimumSeconds(double seconds)
{
_EndTime = DateTime.Now.AddSeconds(seconds);
}
public void Dispose()
{
while (DateTime.Now < _EndTime)
{
Thread.Sleep(100);
}
}
}
Now you can easily make your programs as slow as you want!