We help IT Professionals succeed at work.

Difference between 12 ways of waiting?

deleyd asked
I can call the following 3 methods, which all achieve the same delay of 2 seconds, in 12 different ways.

I'm interested in the underlying details of these 12 different calls differ under the hood. Exactly what does each do behind the scenes and how do they differ?

        private async Task AsyncDelay()
            await Task.Delay(2000);

        private void FooSleep()

        private void TaskDelayWait()

            Task.Run(() => FooSleep()).Wait();
            Task.Run(() => TaskDelayWait()).Wait();
            Task.Run(() => AsyncDelay()).Wait();
            Task.Run(async () => await AsyncDelay()).Wait();
            await AsyncDelay();
            await Task.Run(() => FooSleep());
            await Task.Run(() => TaskDelayWait());
            await Task.Run(() => AsyncDelay());
            await Task.Run(async () => await AsyncDelay());

Open in new window

Watch Question

Chief Technology Ninja
Distinguished Expert 2019

Wew.. this is going to be a tough answer once everyone starts participating in this thread.

Can I cheat a little? I want to take a shortcut. I think I see 3 major factors in all your methods. Most of the methods are just delegates (method pointers) and some nested tasks (maybe with nasty side effects, if not done wisely).

I think Thread.Sleep is self-answering. It puts current thread to "sleep" and brings it "back" after two seconds.Please read https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.sleep?view=netframework-4.8 for more details.

While, Task.Delay creates a tasks which will complete after the specified delay. https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.delay?view=netframework-4.8

When you use Wait for any of the Task, https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.wait?view=netframework-4.8, it causes the calling thread to wait. Which might cause a deadlock, so you would  want to be cautious with them.

Now if you look at your code, you will see at most you are just creating nested Tasks, and when you await a task, and if it does not have anything to "do", it will immediately complete and will return thus the nested task might never run. For example, if the calling thread completes its execution, the last 5 methods will be queued but you will never see the outcome of their execution, if any. 

There is very old article describing this behavior, you might want to have a look at it.


I hope this answer will give you a start.