3

I created a task like the following code

Task task = new(async () =>
{
    // without await Task Delay dont work
    await Task.Delay(TimeSpan.FromSeconds(5));
    Console.WriteLine("Task is down");
});

task.Start();

var awaiter = task.GetAwaiter();

awaiter.OnCompleted(() =>
{
    Console.WriteLine("Task is Completed");
});

Why the task completed first is printed and then the task is down The task is complete and will be printed if my operation is not finished yet

  • Are you playing with awaiters because you think it's the right way of solving your problem, or because you're curious? This isn't really an API you should be working with: that's intended for the compiler-generated code to use. Either `await` that `Task` (preferred), or use `Task.ContinueWith` (which is the older, pre-async/await method) – canton7 May 23 '22 at 15:18
  • This is a question of curiosity, I try to understand asynchronous operations well – mohamad hosein ghelich khani May 23 '22 at 15:20
  • 3
    Oh! You've run into the classic problem that `Task`'s ctor doesn't take a `Func`. So you're effectively just passing an `async void` method to the `Task` ctor: the `Task` has no way of knowing when that async lambda completes, and it will think it's completed when the lambda returns, which happens when it hits the `await`. You need to use `Task.Run` if you're passing `Task`-returning async lambdas around – canton7 May 23 '22 at 15:24
  • I think you're right @canton7 – mohamad hosein ghelich khani May 23 '22 at 15:28
  • Related: [Task constructor vs Task.Run with async Action - different behavior](https://stackoverflow.com/questions/28057654/task-constructor-vs-task-run-with-async-action-different-behavior) – Theodor Zoulias May 23 '22 at 16:17

1 Answers1

3

Because Task constructors are not async aware. No overloads take an function returning a Task so the task created via constructor and async lambda will finish as soon as first await (of unfinished task) is encountered.

And in general you should try avoid using Task constructors and prefer Task.Run instead. From the docs:

This constructor should only be used in advanced scenarios where it is required that the creation and starting of the task is separated.
Rather than calling this constructor, the most common way to instantiate a Task object and launch a task is by calling the static Task.Run(Action) or TaskFactory.StartNew(Action) method.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132