I know I may be downvoted but apparently I just don't understand async-await enough and the questions/answer I found, and the articles I found, didn't help me to find an answer for this question:
How can I make "2" to be printed out? Or actually, WHY doesn't 2 gets printed out, both in await t and in t.Wait() ?:
static Task t;
public static async void Main()
{
Console.WriteLine("Hello World");
t = GenerateTask();
await t;
//t.Wait();
Console.WriteLine("Finished");
}
public static Task GenerateTask()
{
var res = new Task(async () =>
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
});
res.Start();
return res;
}
Edit: I'm creating a task and returning it cause in real-life I need to await on this task later on, from a different method.
Edit2: await Task.Delay is just a placeholder for a real-life await on a different function.
The 2 is actually printed, 10 seconds after 1 is printed. You can observe this if you add Console.ReadLine();
after printing 'Finished'.
The output is
Hello World
1
Finished
2
When you await t
(which is res
in GenerateTask
method) you are awaiting the created Task and not the task that res
created.
You will need to await both the outer task and inner task. To be able to await the inner task you need to expose it. To expose it you need to change the type of the task from Task
to Task<Task>
and the return type from Task
to Task<Task>
.
It could look something like this:
public static async Task Main()
{
Console.WriteLine("Hello World");
var outerTask = GenerateTask();
var innerTask = await outerTask; // what you have
await innerTask; // extra await
Console.WriteLine("Finished");
Console.ReadLine();
}
public static Task<Task> GenerateTask() // returns Task<Task>, not Task
{
var res = new Task<Task>(async () => // creates Task<Task>, not Task
{
Console.WriteLine("1");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("2");
});
res.Start();
return res;
}
The output now is:
Hello World
1
2
Finished
The outer task is not needed.
public static async Task Main()
{
Console.WriteLine("Hello World");
var t = GenerateTask();
await t;
Console.WriteLine("Finished");
Console.ReadLine();
}
public static async Task GenerateTask()
{
Console.WriteLine("1");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("2");
}
It looks like it's because the constructor to new Task only takes some form of an Action (So the Task never gets returned even though it's async). So essentially what you're doing is an Async void with your delegate. Your await Task.Delay(10000)
is returning and the action is considered 'done'.
You can see this if you change the await Task.Delay(10000)
to Task.Delay(10000).Wait()
and remove the async from the delegate.
On another note though, I've never personally seen or used new Task before. Task.Run()
is a much more standard way to do it, and it'll allow for the await to be used. Also means you don't have to call Start() yourself.
Also you might already know this but, in this specific case you don't need a new task at all. You can just do this:
public static async Task GenerateTask()
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
}
Regarding your edits
Replacing your GenerateTask
with what I wrote should do what you want. The async/await will turn your method into a Task that has started execution. This is exactly what you are trying to do so I'm not quite sure what you are asking with your edits.
The task returned from GenerateTask
can be awaited whenever you want, or not awaited at all. You should almost never need to do new Task()
. The only reason I can think is if you wanted to delay execution of the task until later, but there would be better ways around it rather than calling new Task()
.
If you use the way I showed in your real-life situation, let me know what doesn't work about it and I'll be happy to help.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With