await on task to finish, with operations after the 'await' - c#

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.

Printing '2'
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
What is happening?
When you await t (which is res in GenerateTask method) you are awaiting the created Task and not the task that res created.
How to fix (fancy way)
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
How to fix (easy way)
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.

You should use Task.Run() rather than creating a Task directly:
public static Task GenerateTask()
{
return Task.Run(async () =>
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
});
}
Task.Start() doesn't work because it doesn't understand async delegates, and the returned task just represents the beginning of the task.
Note that you can't fix this by using Task.Factory.StartNew() either, for the same reason.
See Stephen Cleary's blog post on this issue, from which I quote:
[Task.Factory.StartNew()] Does not understand async delegates. This is actually the same as
point 1 in the reasons why you would want to use StartNew. The problem
is that when you pass an async delegate to StartNew, it’s natural to
assume that the returned task represents that delegate. However, since
StartNew does not understand async delegates, what that task actually
represents is just the beginning of that delegate. This is one of the
first pitfalls that coders encounter when using StartNew in async
code.
These comments also apply to the Task constructor, which also doesn't understand async delegates.
However, it's important to note that if you are already awaiting in the code and you don't need to parallelise some compute-bound code, you don't need to create a new task at all - just using the code in your Task.Run() on its own will do.

Related

Async method blocking on unawaited task

In my current project, I have a piece of code that, after simplifying it down to where I'm having issues, looks something like this:
private async Task RunAsync(CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask();
}
private Task<bool> FakeTask()
{
return Task.FromResult(false);
}
If I use this code without awaiting, I end up blocking anyway:
// example 1
var task = RunAsync(cancel); // Code blocks here...
... // Other code that could run while RunAsync is doing its thing, but is forced to wait
await task;
// example 2
var task = RunAsync(cancelSource.Token); // Code blocks here...
cancelSource.Cancel(); // Never called
In the actual project, I'm not actually using FakeTask, and there usually will be some Task.Delay I'm awaiting in there, so the code most of the time doesn't actually block, or only for a limited amount of iterations.
In unit testing, however, I'm using a mock object that does pretty much do what FakeTask does, so when I want to see if RunAsync responds to its CancellationToken getting cancelled the way I expect it to, I'm stuck.
I have found I can fix this issue by adding for example await Task.Delay(1) at the top of RunAsync, to force it to truly run asynchronous, but this feels a bit hacky. Are there better alternatives?
You have an incorrect mental picture of what await does. The meaning of await is:
Check to see if the awaitable object is complete. If it is, fetch its result and continue executing the coroutine.
If it is not complete, sign up the remainder of the current method as the continuation of the awaitable and suspend the coroutine by returning control to the caller. (Note that this makes it a semicoroutine.)
In your program, the "fake" awaitable is always complete, so there is never a suspension of the coroutine.
Are there better alternatives?
If your control flow logic requires you to suspend the coroutine then use Task.Yield.
Task.FromResult actually runs synchronously, as would await Task.Delay(0). If you want to actually simulate asynchronous code, call Task.Yield(). That creates an awaitable task that asynchronously yields back to the current context when awaited.
As #SLaks said, your code will run synchronously. One thing is running async code, and another thing is running parallel code.
If you need to run your code in parallel you can use Task.Run.
class Program
{
static async Task Main(string[] args)
{
var tcs = new CancellationTokenSource();
var task = Task.Run(() => RunAsync("1", tcs.Token));
var task2 = Task.Run(() => RunAsync("2", tcs.Token));
await Task.Delay(1000);
tcs.Cancel();
Console.ReadLine();
}
private static async Task RunAsync(string source, CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask(source);
}
private static Task<bool> FakeTask(string source)
{
Console.WriteLine(source);
return Task.FromResult(false);
}
}
C#'s async methods execute synchronously up to the point where they have to wait for a result.
In your example there is no such point where the method has to wait for a result, so the loop keeps running forever and thereby blocking the caller.
Inserting an await Task.Yield() to simulate some real async work should help.

Why await an async function directly not work without assigning it to a Task variable

Typically, I do the following
public static async Task dosth()
{
List<Task> job = new List<Task>();
for (int i = 0; i < 3; i++)
{
job.Add(sleep());
}
Task.WhenAll(job.ToArray());
}
static async Task sleep()
{
await Task.Delay(1000);
Console.WriteLine("Finish new");
}
It works smoothly, no problem. But when I do a review on my own code (trying using other syntax to do the same job), I suddenly figure out the following two are different.
public static async Task dosthA()
{
//This will be working synchronously, take 3 seconds.
await sleep();
await sleep();
await sleep();
//This will be working asynchronously, take 1 second only.
Task A = sleep();
Task B = sleep();
Task C = sleep();
await A;
await B;
await C;
}
Why assigning the async function to a new variable make difference? I originally think they are the same.
Update
Why it is confusing me is, actually in Microsoft doc on Async-await,
They stated the following in their code.
// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();
They are actually different, why they use //or , in a single statement, just because it makes no different in their own example?
This is because when you are returning a running Task when you call Sleep() even when you're assigning to a variable.
The confusion is that the Task does not begin if you assign it to a variable (A, B, or C) until you call await A; but that's not true. As soon as you assign sleep(); to A, sleep() was called; therefore the Task in the sleep() method is running. Assigning it to a variable or not the Task begins when you call the method; because in the method you start the Task.
Knowing this; when you call:
await A;
await B;
await C;
A, B, and C, have already starting simultaneously... After awaiting A it is most likely B, and C have also completed or are milliseconds from completing.
There are situations where you can reference a Task that hasn't started yet but you would have to purposely return a non-running Task to do that.
To answer the edit to your question also.
Tasks have a method called GetAwaiter() which returns a TaskAwaiter. In C# when you write var task = sleep(); then you're assigning the actual Task to the task variable. All the same when you write await sleep(); the compiler does some cool stuff and it actually calls the Task.GetAwaiter() method; which is subscribed to. The Task will run and when it is complete the TaskAwaiter fires the continuation action. This can't be explained in a simple answer but to know the outer logic helps.
Among other things the TaskAwaiter implements ICriticalNotifyCompletion which in turn implements INotifyCompletion. Both have one method each, OnCompleted(Action) and UnsafeOnCompleted(Action) (you can guess which is which by naming convention).
Another thing to note is that Task.GetAwaiter() returns a TaskAwaiter but Task<TResult>.GetAwaiter() returns a TaskAwaiter<TResult>. There's not a strong difference in the two but there is a difference in the GetResult() method of the two tasks; which is what's called while marshalling back to the proper threading context. The TaskAwaiter.GetResult() returns void and the TaskAwaiter<TResult>.GetResult() returns TResult.
I feel like if I push further into this I'll have to write pages to explain it all in detail... Hopefully just explaining your question and pulling the curtain back a little bit will shed enough light to help you both understand and dig deeper if you're more curious.
Ok, so based on the comment below I want to describe my answer a little bit further.
I'll start this simple; let's just make a Task; one that isn't running, and look at it first.
public Task GetTask()
{
var task = new Task(() => { /*some work to be done*/ });
//Now we have a reference to a non-running task.
return task;
}
We can now call code like:
public async void DoWork()
{
await GetTask();
}
… but we'll be waiting forever; until the application ends, because the Task was never started. However; we could do something like this:
public async void DoWork()
{
var task = GetTask();
task.Start();
await task;
}
… and it will await the running Task and continue once the Task is complete.
Knowing this you can make as many calls to GetTask() as you like and you'll only be referencing Tasks that have not started.
In your code it's just the opposite, which is fine, as this is the most used way. I encourage you to make sure your method names notify the user of how you're returning the Task. If the Task is already running the most common convention is the end the method name with Async. Here's another example doing it with a running Task for clarity.
public Task DoTaskAsync()
{
var task = Task.Run(() => { /*some work to be done*/ });
//Now we have a reference to a task that's already running.
return task;
}
And now we will most likely call this method like:
public async void DoWork()
{
await DoTaskAsync();
}
However; note that if we simply want to reference the Task just like we did earlier, we can, the only difference is this Task is running where the one prior was not. So this code is valid.
public async void DoWork()
{
var task = DoTaskAsync();
await task;
}
The big take away is how C# handles the async / await keywords. async tells the compiler that the method is going to become a continuation of a Task. In short; the compiler knows to look for all await calls and put the rest of the method in a continuation.
The await keyword tells the compiler to call the Task.GetAwaiter() method on the Task ( and basically subscribe to the INotifyCompletion and ICriticalNotifyCompletion) to signal the continuation in the method.
And this I wanted to add just incase you weren't aware. If you do have more than one task that you want to await but would rather await one task as if they were all one then you can do that with Task.WhenAll() So instead of:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await taskA;
await taskB;
await taskC;
You could write it a little cleaner like so:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await Task.WhenAll(taskA, taskB, taskC);
And there are more ways of doing this sort of thing built in; just explore it.

Does a method has to be async when invoked inside an async method?

Lets say I have a method defined as follows:
public async Task CreateUser()
{
await GetUserDetails();
GetUserOrder();
}
private void GetUserDetails() {
private void GetUserOrder() {
Does the method GetUserDetails(); and GetUserOrder() have to be async as well to avoid UI blocking ?
I cannot await the GetUserDetails() method since it is not async. How can I achieve this in c# ? I want to ensure all these methods are invoked step by step.
The relevant question is in a comment:
How can I ensure all my methods are invoked completely sequentially?
The fact that you're asking the question indicates that you don't understand what "await" is. Await is the sequencing operation on a asynchronous workflows. An await means this workflow will not proceed until the awaited task is complete. It's an asynchronous wait, hence the name await.
Consider this question: in a synchronous workflow, what is the sequencing operation?
No, really, give it some thought.
.
.
.
It is ;. When you say
fResult = foo();
bResult = bar();
qResult = qux();
that means that foo has to finish completely before bar can begin. That is not true for asynchronous workflows. If we have
fTask = fooAsync();
bTask = barAsync();
qTask = quxAsync();
Then the asynchronous operations can complete in any order. If we say
await fooAsync();
await barAsync();
await quxAsync();
Then barAsync will not start until fooAsync's task completes. await sequences the asynchronous workflow. The difference is that the thread can continue to do other unrelated work while asynchronously waiting for foo to complete, which is not true in a synchronous workflow; in a synchronous workflow the thread is already busy computing the foo result, so it can't do other work.
yes if you want to wait than you have to write await for that methods also. because after first await your code agian will be synchronous ..and if UI thread than it will run on it.
1.you code will be , so by this code you code become asynchronous for GetUserORder also. you just have to wrap method in Task construct and return
public async Task CreateUser()
{
await GetUserDetails();
await Task.Factory.SartNew(()=> GetUserOrder());
}
2.or you can do this also
public async Task CreateUser()
{
await Task.Factory.SartNew(()=>{
GetUserDetails();
GetUserOrder(); });
}
3.or you can do like this also, in below code will not wait for getuserorder method and excute await one method
public async Task CreateUser()
{
Task.Factory.SartNew(()=> GetUserOrder()).ContinueWith((t)=> Console.WriteLine("Completed");
await GetUserDetails();
}
4.or last one variation, here you start GetUserOrder first and dont wait for it than you call GetUserDetails in async fashion , and if you want to work on GetUserOrder method want to wait just use Wait method.
public async Task CreateUser()
{
var task = Task.Factory.SartNew(()=> GetUserOrder());
await GetUserDetails();
if(!task.IsCompleted)
task.Wait();
}
in your case you can go for 3 and if you want to wait go for 4th one.
As you asked me in comment what is difference between Task.Run and statnew method -: for that you can check this SO question : Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()
You should put await only in front of async methods. To run a synchronous one that you don't want to wait, you can use a new thread from the tread pool:
new Thread(() => DoSomething()).Start();
or
Task.Factory.SartNew(()=> DoSomething());
Here is the help page: https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx
Otherwise, your call to GetUserDetails will have to finish before you execute the next line.

async within a LINQ code - Clarification?

Almost every SO's answer regarding this topic , states that :
LINQ doesn't work perfectly with async
Also :
I recommend that you not think of this as "using async within LINQ"
But in Stephen's book there is a sample for :
Problem: You have a collection of tasks to await, and you want to do some
processing on each task after it completes. However, you want to do
the processing for each one as soon as it completes, not waiting for
any of the other tasks.
One of the recommended solutions was :
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(async t =>
{
var result = await t;
Trace.WriteLine(result);
}).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
Question #1:
I don't understand why now async inside a LINQ statement - does work . Didn't we just say "don't think about using async within LINQ" ?
Question #2:
When the control reaches the await t here — What is actually happen? Does the control leaves the ProcessTasksAsync method ? or does it leaves the anonymous method and continue the iteration ?
I don't understand why now async inside a LINQ statement - does work . Didn't we just say "don't think about using async within LINQ" ?
async mostly doesn't work with LINQ because IEnumerable<T> extensions don't always infer the delegate type properly and defer to Action<T>. They have no special understanding of the Task class. This means the actual async delegate becomes async void, which is bad. In the case of Enumerable.Select, we have an overload which returns a Func<T> (which in turn will be Func<Task> in our case), which is equivalent to async Task, hence it works fine for async use-cases.
When the control reaches the await t here — What is actually happen? Does the control leaves the ProcessTasksAsync method ?
No, it doesn't. Enumerable.Select is about projecting all elements in the sequence. This means that for each element in the collection, await t which will yield control back to the iterator, which will continue iterating all elements. That's why you later have to await Task.WhenAll, to ensure all elements have finished execution.
Question 1:
The difference is that each task is continued with additional processing which is: Trace.WriteLine(result);. In the link you pointed to, that code does not change anything, just creates overhead of awaiting and wrapping with another task.
Question 2:
When the control reaches the await t here — What is actually happen?
It awaits for the result of ProcessTasksAsync's task, then continue with Trace.WriteLine(result);. We can say that the control leaves the ProcessTasksAsync method when we have the result and the processing is still inside the anonymous method.
At the end, we have await Task.WhenAll(processingTasks); which will await for all tasks including the additional processing (Trace.WriteLine(result);) to complete before continuing but each task does not await for the others to continue executing: Trace.WriteLine(result);
It will be better this way:
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
static async Task AwaitAndProcessAsync(Task<int> task)
{
var result = await task;
Console.WriteLine(result);
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(AwaitAndProcessAsync).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
Array of Task, because AwaitAndProcessAsync returns Task.

How do I create a Task that uses await inside the body that behaves the same as the synchronous version when Wait is called?

I have some code that creates a task that does some slow work like this:
public static Task wait1()
{
return new Task(() =>
{
Console.WriteLine("Waiting...");
Thread.Sleep(10000);
Console.WriteLine("Done!");
});
}
In the real implementation, the Thread.Sleep will actually be a web service call. I would like to change the body of the method can use await (so it does not consume a thread during the network access/sleep). My first attempt (based on shotgun-debugging the compile errors) was this:
public static Task wait2()
{
return new Task(async () =>
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
});
}
However; this task doesn't seem to behave the same as the first one, because when I call .Wait() on it; it returns immediately.
Below is a full sample (console app) showing the differences (the app will end immediately when the second task starts).
What do I need to do so that I can call Start and Wait on a Task which happens to have code using await inside it? The tasks are queued and executed later by an agent, so it's vital that the task is not auto-started.
class Program
{
static void Main(string[] args)
{
var w1 = wait1();
w1.Start();
w1.Wait(); // This waits 110 seconds
var w2 = wait2();
w2.Start();
w2.Wait(); // This returns immediately
}
public static Task wait1()
{
return new Task(() =>
{
Console.WriteLine("Waiting...");
Thread.Sleep(10000);
Console.WriteLine("Done!");
});
}
public static Task wait2()
{
return new Task(async () =>
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
});
}
}
It seems like this isn't possible! See alexm's answer here:
Tasks returned by async methods are always hot i.e. they are created in Running state.
:-(
I've worked around this by making my agent queue Func<Task>s instead, and the overload that receives a task simply queues () => task. Then; when de-queing a task, I check if it's not running, and if so, start it:
var currentTask = currentTaskFunction();
if (currentTask.Status == TaskStatus.Created)
currentTask.Start();
It seems a little clunky to have to do this (if this simple workaround works; why the original restriction on async methods always being created hot?), but it seems to work for me :-)
You could write this as:
public static async Task Wait2()
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
}
In general, it's rarely a good idea to ever use new Task or new Task<T>. If you must launch a task using the ThreadPool instead of using the async/await language support to compose one, you should use Task.Run to start the task. This will schedule the task to run (which is important, tasks should always be "hot" by conventions).
Note that doing this will make it so you don't have to call Task.Start, as well.
To help you understand this realize that async / await essentially does not create a new thread but rather it schedules that portion of code to be ran at an available point in time.
When you create the new Task(async () => ...) you have a task that run an async method. When that inner async method hits an await the 'new Task' is considered complete because the rest of it has been scheduled. To help you understand better place some code (a lot if wanted) in the 'new Task' before the await command. It will all execute before the application terminates and once await is reached that task will believe it has completed. It then returns and exits the application.
The best way to avoid this is to not place any task or async methods inside of your task.
Remove the async keyword and the await keyword from the method and it will work as expected.
This is the same as creating a callback if you're familiar with that.
void MethodAsync(Action callback)
{
//...some code
callback?.Invoke();
}
//using this looks like this.
MethodAsync(() => { /*code to run when complete */});
//This is the same as
Task MethodAsync()
{
//... some code here
}
//using it
await MethodAsync();
/*code to run when complete */
The thing to understand is that you're creating a new task within a task basically. So the inner 'callback' is being created at the await keyword.
You're code looks like this..
void MethodAsync(Action callback)
{
//some code to run
callback?.Invoke(); // <- this is the await keyword
//more code to run.. which happens after we run whoever is
//waiting on callback
}
There's code missing obviously. If this doesn't make sense please feel free to contact me and I'll assist. async / await (meant to make things simpler) is a beast to wrap your head around at first. Afterward you get it then it'll probably be your favorite thing in c# since linq. :P
Try this:
public async static Task wait2()
{
Console.WriteLine("Waiting...");
await Task.Delay(2000);
Console.WriteLine("Done!");
}
But we aware that the task is already started so you don't have to call start:
var w2 = wait2();
//w2.Start();
w2.Wait();
I think the problem with your wait2 function is that is creating 2 task, the one in new Task(...) and another in Task.Delay(). You are waiting for the first one, but you are not waiting for the inner one.

Categories

Resources