2

Every now and then I see someone delaying an action by a certain number of milliseconds to ensure it is working.

Something like:

doSomethingInHtml();
timer.schedule(100); // delay for 100 milliseconds to ensure stuff was rendered
doSomethingElse();

But, while it may work now, that 100 can either be too much, therefore freezing the app with no good reason, or in some unexpected circumstances can be too little, and the render (in this example) might take longer.

I strongly believe that we should never delay like that - we should find ways to ensure whatever the dependency, it got finished, without delaying blindly and hoping it finished.

Is there ever any good reason to delay a fixed amount of time in order to wait for something to finish as opposed to actually checking if that action finished?

1
  • The app doesn't freeze if other threads are still running and the UI responsive. If often makes sense to pause a specific thread for a set time, for example the pause between each "drop" in Tetris. Outside of UI it is probably not as useful.
    – JacquesB
    Jul 30, 2020 at 13:06

3 Answers 3

5

Yes. To delay to give time for completion prior to checking.

Yes. To animate, because humans see in the order of ~80hz.

Yes. To throttle, running at 100% isn't always the right option.

No. There is usually another way to do everything above that is better in every way. Except all of those ways are far more complex, more likely to be ridden with bugs, and may be overkill when the target platform is known wasting precious resources to synchronisation.

Of course a new target platform will convert most decisions into bugs, or legacy sub-optimal solutions anyway.

So choose a general sub-optimal but adaptive solution or choose the specific optimal but rigid and ungeneral solution. Welcome to software Engineering where we trade these off.

3
  • 1
    Doesn't the "to animate" argument rely on the frame render itself also taking a fixed amount of time then? Which you can't really guarantee, so a fixed time delay isn't the best approach. Hence the whole "delta time" approach in game development.
    – Flater
    Jul 30, 2020 at 9:42
  • @Flater Maybe. But sometimes you just don't care about the exact update rate; you only want something to animate.
    – Simon B
    Jul 30, 2020 at 10:13
  • @Flater You are indeed right, on today's modern machines this is indeed a better way to do it. But I remember machines from my youth, wasting the cycles (and omg memory!) on figuring out how much longer to wait, already meant you should be rendering again, or had to wait for the system to page (assume it could and even then that was sooooo sloooooooooooooow). But that is why we are engineers, we can see several solutions, then we figure out which one to use given the observable trade offs realising that it will be a poor/bad decision when the situation changes.
    – Kain0_0
    Jul 30, 2020 at 10:27
2

TL;DR The core of your argument makes sense but you're applying it too broadly.


You're right that the fixed amount, whatever the fixed amount is, is going to be an arbitrary approximation. But sometimes an arbitrary approximation is all you need.

For example, a service that repeatedly polls an external resource, either until some condition is met, or indefinitely. The simplest way to implement that is to have a loop (usually while) which contains a fixed delay in its body. Without that delay, you'd be polling your resource way too quickly.

I strongly believe that we should never delay like that - we should find ways to ensure whatever the dependency, it got finished, without delaying blindly and hoping it finished.

Look back at my example. The resource we're waiting for is external to our application. How can we know that it's complete, if not by polling it? But we don't want to poll thousands of times per second. Therefore, we need to slow down our polling. And how do we do that? By delaying.

The core of your argument makes sense but you're applying it too broadly.

Generally, async/await will provide better knowledge on when a resource has finished. However, there's is no guarantee that an awaited task will be resumed exactly when it is finished. It may take longer if there are no threads available when the awaited task completed.
A delay, more specifically a sleeping thread, is guaranteed to resume exactly after it ends, because it never abandoned its thread so it can ensure that thread's availability when it wants to resume. There may be use cases where this is preferable.

When dealing with frame rendering or animation, using delta time is generally more preferably due to the ability to dynamically adapt to the timing between frames (and how to handle an unexpectedly longer/shorter timing).
But delta time is not a simple thing to implement, and an implementation of that complexity is not always warranted. If you're making a slideshow where the picture changes once every few seconds, an fixed delay would be perfectly appropriate as humans won't notice the difference.

Similar to delta time, you could implement a stopwatch, track the time a certain process took, and calculate your delay time based off of it, e.g. await Task.Delay(5000 - sw.ElapsedMilliseconds).

But again the question is what you stand to gain by that dynamically calculated delay time. From an engineering perspective it is more elegant, but just because something is more elegant does not mean it is more useful.
That implementation brings with it a bunch of new considerations. Stopwatches are may not have the precision you're looking for. You have to manage stopwatch resources everywhere. What if the measured task takes longer than your maximum delay time? How many bugs are you going to encounter before you regret taking this unnecessary-but-more-elegant approach?

0

It’s Ok if you can calculate ahead exactly how long the delay should be. For example, if a window is supposed to stay visible for 1 second, I want to hide it, and it has been visible for 0.523 seconds, a delay of 0.477 seconds is fine. There are other situations like throttling to avoid pointless work.

If you are in a situation “without a delay the app crashes, with a long delay it slows down”, then a fixed delay is usually a hack. If you manage a delay that works reliably and doesn’t slow things down noticeably, that’s ugly but can be Ok. But the best thing to do is always: Find out why an operation needs delaying, and if at all possible wait until the operation can be performed safely. Mutexes, semaphores etc. can be helpful.

If the problem is in third party code, it may be easy and quick To check the dangerous condition, but impossible to get notified if it goes away. Instead of a fixed delay you may use a timer that checks repeatedly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.