1

I expect the following code to be blocked for almost 5 secs, but it is not. It immediately prints. Isn't Result operation blocking?

class Program
{
    static void Main()
    {
        // Return a value type with a lambda expression
        Task<int> task1 = Task<int>.Factory.StartNew(() => Task.Delay(5000).Id + 100);
        int i = task1.Result;
        Console.WriteLine(i);
    }
}
Caius Jard
  • 72,509
  • 5
  • 49
  • 80
Hax
  • 133
  • 9
  • What's the intention behind the `Task.Delay(5000).Id + 100` expression? Adding a number to an ID seems nonsensical. IDs, much like phone numbers, are not intended for doing math. – Theodor Zoulias Dec 31 '21 at 08:25
  • @Theodor I assume it's just to give the task an int result that involves the contents of the operation in some way, not for any practical use – Caius Jard Dec 31 '21 at 08:32
  • 3
    `Task.Delay` returns a `Task` that you have to wait on in order to "block" for the specified amount of time. – Sean Dec 31 '21 at 08:36
  • 1
    Would it make sense to you if I said "change your code to say `Task task1 = Task.Factory.StartNew(() => { var t = Task.Delay(5000); t.Wait();return t.Id + 100;});` ? – Caius Jard Dec 31 '21 at 08:42

2 Answers2

5

This code is not waiting for Delay to finish. It starts the delay and then return immediately Id+100. So, when the code reaches the Result operation, the task1 is almost always is in Completed state, so you get Result immediately.

You can try following to get desired behaviour

Task<int> task1 = Task.Run(async () => await Task.Delay(5000).Id + 100);
int i = task1.Result;

Or better, use await instead of Result everywhere

Task<int> task1 = Task.Run(async () => await Task.Delay(5000).Id + 100);
int i = await task1;

or even

int i = await Task.Delay(5000).Id + 100

(but I'm unsure here as you may have more logic inside the task in actual code)

Serg
  • 3,454
  • 2
  • 13
  • 17
  • 1
    Are you sure about using the `Task.Factory.StartNew` [with asynchronous lambda](https://stackoverflow.com/questions/24777253/waiting-for-async-await-inside-a-task)? – Theodor Zoulias Dec 31 '21 at 08:55
  • 2
    Hm. yes, you are correct - `StartNew` will not work with async, only `Task.Run` will. I corrected the answer. Thank you! – Serg Dec 31 '21 at 09:08
  • what is the difference btw `task1.Result` and `await task1;` ? Don't they allow the caller thread to continue? such as `Console.WriteLine("it prints before task1.Result"); task1.Result` – Hax Dec 31 '21 at 09:10
  • `Result` will block the current thread until the task will finish and result will be awailable. `Await` will wait asynchrnously and let the current thread to do other things then resume execution from `await` point after the result will be awailable. See here for more details https://stackoverflow.com/questions/27464287/what-is-the-difference-between-await-taskt-and-taskt-result – Serg Dec 31 '21 at 09:13
1

To me ContinueWith seems more natural for what you're trying to do:

Task<int> t = Task.Delay(5000).ContinueWith(delayTask => delayTask.Id + 100);
Console.WriteLine(t.Result);

This will execute the delay task and then execute the lambda in ContinueWith after the delay is complete.

IllusiveBrian
  • 3,105
  • 2
  • 14
  • 17
  • 1
    Be careful with the `ContinueWith` method. If you have to use it, you [should specify](https://stackoverflow.com/questions/69254023/channel-multiple-producers-and-consumers/69254906#69254906) the `scheduler` argument to avoid unpleasant surprises. – Theodor Zoulias Jan 01 '22 at 02:03