I am new in async programming and my question might look silly. Can anybody, please, explain how async calls work in the following pseudo code example?
public async Task MyMethod()
{
while(true)
{
await Method1();
//do something in MyMethod
await Task.Delay(10000);
}
}
private async Task Method1()
{
//do something in Method1 before await
await Method2();
//do something in Method1 after await
}
private async Task Method2()
{
//do something in Method2 before await
await LongRunMethod();
}
In my understanding, the program works like this
MyMethod() calls Method1() in infinite loop
Method1() runs "do something in Method1 before await"
Method1() starts Method2() and returns control to MyMethod()
MyMethod() starts 10000 ms delay and returns control to its caller
Method2() completes "do something in Method2 before await", starts LongRunMethod() and returns control to MyMethod1()
Method1() completes "do something in Method1 after await". What method does get control after that?
LongRunMethod() finishes its work
Method2() finishes its work. Does it return control to Method1()?
After 10000ms, everything repeats from step 1.
My questions are
Is the above steps sequence correct?
What methods do get control after Method1() and Method2() finish their work in steps 6 and 8?
What is going to happen if LongRunMethod() runs longer than 10000ms?
Thank you
Is the above steps sequence correct?
No.
The correct sequence is
MyMethod calls Method1.
Method1 does the code before the call to Method2.
Method1 calls Method2.
Method2 does the code before the call to LongRunMethod.
Method2 calls LongRunMethod.
LongRunMethod returns a task to Method2.
Method2 interrogates the task to see if it is complete. Let's suppose it is not.
Method2 signs up "do no additional work, and then mark method2's task as complete" as the continuation of the task just returned, and returns its task to Method1.
Method1 interrogates the task just returned from method2. Let's suppose it's not complete. It assigns the work that happens after the await as the continuation of method1's task, and returns that task to its caller.
MyMethod interrogates the task just returned from Method1. Let's suppose it's not complete. It signs up the remainder of that work to the continuation of its task, and returns that task to its caller.
That caller, whatever it is, does whatever work it does.
At some point in the future, LongRunMethod's task completes asynchronously and requests that its continuation be resumed in the appropriate context.
Eventually that context gets to run code, and it runs the continuation of the LongRunMethod task, which is, recall, to do no work and then mark the Method2 task as complete.
It does so. Method2's task is now complete, so it requests its continuation to run on the appropriate context.
Eventually that runs. Recall that Method2 task's continuation is to run the remainder of Method1. It does so, and then marks Method1's task as complete. That requests that Method1's task run its continuation.
Eventually that continuation runs. Its continuation is to call Task.Delay.
Task.Delay returns a task. MyMethod interrogates the task. It's not complete. So it signs up "go back to the top of the loop" as the continuation of that task. It then returns.
Whatever code triggered the continuation of LongRunMethod's task keeps doing work. At some point ten seconds in the future the delay task completes and requests that its continuation executes.
Eventually the continuation executes on the appropriate context. The continuation is "go back to the top of the loop", and the whole thing starts over.
Note that the task returned by MyMethod never completes normally; if any of those tasks throw exceptions then it completes exceptionally. For simplicity I've ignored the checks for exceptional continuation in your example, since there is no exception handling.
What methods do get control after Method1() and Method2() finish their work?
The remainder of Method1 eventually gets control after the task returned by Method2 is completed. MyMethod eventually gets control after the task returned by Method1 is completed. The exact details of when the continuations are scheduled depends on the context in which the code is running; if they're on the UI thread of a form, that's very different than if they're in worker threads on a web server.
What is going to happen if LongRunMethod() runs longer than 10000ms?
I think you mean what happens if the task returned by LongRunMethod does not complete for more than ten seconds. Nothing particularly interesting happens then. The delay is not started until after LongRunMethod's task is done. You awaited that task.
I think you fundamentally do not understand what "await" means. You seem to think that "await" means "start up this code asynchronously", but that is not at all what it means. The code is already asynchronous by assumption. Await manages asynchrony; it does not create it.
Rather, await is an operator on tasks, and it means if this task is complete then keep going; if this task is not complete then sign up the remainder of this method as the continuation of that task and try to find some other work to do on this thread by returning to your caller.
No code that is after an await executes before the awaited task is completed; await means asynchronously wait for the completion of the task. It does NOT mean "start this code asynchronously". Await is for declaring what points in an asynchronous workflow must wait for a task to finish before the workflow can continue. That's why it has "wait" in the name.
Related
I have issues understanding a detail about async programming in C#.
Lets say I have a common async method, that has a few await statements in it. Lets say I have another method, which is not async, but calls the first method.
public void DoSomething(){
DoSomethingAsync()
...
}
public async Task DoSomethingAsync(){
...
await ...
...
}
I know i could just use Wait() or some other synchronization technique, but i dont just want to throw stuff at problems without knowing what happens.
Will DoSomething continue execution before DoSomethingAsync is completed? I know that this would happen if DoSomething were to be declared async, but it isn't.
Or to be more general: Can synchronous methods continue their execution before an asynchronous sub-call has completed?
TL;DR It continues
Can synchronous methods continue their execution before an
asynchronous sub-call has completed?
Of course it can, if a synchronous method has to wait an asynchronous method to finish, what's the purpose of going asynchronous? (It can wait as well, depending on what you want to achieve)
async/await pattern in your code will create a state machine that can be recovered later. By the time your code hits await, the task you await on will be pushed to the task scheduler and might be executed in some threadpool thread. The async method returns and let the synchronous method continue.
When the task is finished, the state machine recovers the context, and everything in DoSomethingAsync after await continues. On which thread it would run? This depends on if you set ConfigureAwait and the threading model of your program. For example, for a WPF application, by default, it comes back to the main thread, and that's why wait + await can lead to deadlocks.
What happens is:
DoSomething calls DoSomethingAsync.
Then a synchronous! order starts until the first "await" is reached.
With this await, the DoSomethingAsync returns a Task object the has status "not finished yet". But as you do not assign this return value and also do nothing else special your DoSomething continues.
In the absence of the await operator this method will behave as if this call is not awaited, execution of the current method continues before the call is completed
The compiler will warn you:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs4014?f1url=%3FappId%3Droslyn%26k%3Dk(CS4014)
Can synchronous methods continue their execution before an asynchronous sub-call has completed?
As others have noted, the answer to this is "yes".
All asynchronous methods begin executing synchronously. They return a task that represents the completion of that asynchronous method. The task is completed when the asynchronous method is completed. If the asynchronous method returns a result, then the task is completed with a result value. If the asynchronous method throws an exception, then the task is completed with an exception (i.e., faulted).
However, this also means that there is are some problems with the code you've posted. Specifically, it's doing a kind of "fire and forget", and that's dangerous.
This code is just ignoring the task returned from DoSomethingAsync:
public void DoSomethingElse(){
DoSomethingAsync()
...
}
So that means it's saying "start doing something" and it's also saying "I don't care if or when that 'something' completes, and I don't care if it throws an exception". There are a couple problems with this: 1) since your app doesn't know when "something" completes, it can't know when it's safe to shut down, and 2) your app won't be notified if "something" fails.
In the vast, vast majority of scenarios, that means the app has bugs. "Fire and forget" is only appropriate when doing an operation where it doesn't actually matter if the operation fails or isn't even completed. There are very few operations where this is the case.
This is why - as a general rule - tasks should eventually be awaited. If you want to start an operation and then do other things and then await that operation to complete, that's not uncommon:
public async Task DoSomethingElseAsync() {
var task = DoSomethingAsync();
... // other synchronous/asynchronous work.
await task; // asynchronously wait for DoSomethingAsync to complete,
// and propagate any exceptions.
}
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.
I'm currently developing a system where I'll need to connect a couple of clients to a server, which means that I will need to run a background task for each client. The last project I built was with APM, but I am now trying out to build everything around the new and better TAP.
My question is, how do I run many long-running asynchronous functions within a synchronous function? I know that I could use Task.Run(), but it feels like there's a better way. If I just try to run the function as it is, the warning ...
"Because this call is not awaited, execution of the current method continues before the call is completed."
... appears, which means that I'm doing something wrong.. or do I? What is the most efficient and correct way to make all of the clients run at the same time?
class AsyncClient
{
public AsyncClient()
{
...
}
public async Task RunAsync(IPAddress address, int port)
{
... waiting for data
}
}
static void Main(string[] args)
{
List<AsyncClient> clients = new <AsyncClient>();
clients.Add(new AsyncClient());
clients.Add(new AsyncClient());
clients.Add(new AsyncClient());
foreach (var c in clients)
{
// What is the best way to start every async tasks?
c.RunAsync("127.0.0.1", "8080");
// ^ This gives the warning "Because this call is not awaited,
// execution of the current method continues before the call is completed."
}
}
Thanks!
First you should change your Main method to be async:
static async Task Main(string[] args)
Then you can await the asynchronous operations.
To allow them to run in parallel, you can make use of LINQ Select:
IEnumerable<Task> tasks = clients.Select(c => c.RunAsync("127.0.0.1", "8080"));
await Task.WhenAll(tasks);
Task.WhenAll returns a new Task that completes when all the provided Tasks have completed.
Without awaiting the Tasks, there is a good chance that your Main method will complete, and hence the program will exit, before the Tasks have competed,
So you have a non async method, and in this non-async method you want to call async methods.
Usually a method is async, because somewhere deep inside your thread has to wait for another lengthy process to finish. Think of a file to be written, a database query to be executed, or some information to be fetched from the internet. Those are typically functions where you'll find async methods next to the non-async methods.
Instead of waiting idly for the other process to finish its task, the caller of the method receives control to do other things, until it sees an await. Control is given to the caller until it sees an await etc.
So if you want to do other things while the other process is executing its task: simply don't await. The problem is of course: you want to know the result of the other task, before your function exits. If you don't if will be hard to define the post condition of your method.
void MyMethod()
{
Task<int> taskA = MethodAasync(...);
// you didn't await, you are free to do something else, like calling another async method
Task<double> taskB = MethodBasync(...);
DoSomethingUseful();
// if here, you need the result of taskA. Wait until it is ready
// this blocks your thread!
taskA.Wait();
int resultA = taskA.Result();
ProcessResult(resultA);
// if desired, you can wait for a collection of tasks:
Task[] tasksToWaitFor = new Task[] {taskA, taskB};
Task.WaitAll(tasksToWaitFor);
int resultA = taskA.Result();
double resultB = taskB.Result();
ProcessResults(resultA, resultB);
}
Even if you are not interested in the result of the tasks, it is wise to wait for them to finish. This allows you to react on exceptions.
By the way, did you see that I did not call Task.Run! What happens, is that my thread enters MethodAasync until it sees an await. Then the procedure gets back control, so it enters MethodBasync until is sees an await. Your procedure gets back control to DoSomethingUseful.
As soon as the other process (database query, write file, etc) is finished, one of the threads of the thread pool continues processing the statements after the await, until it meets a new await, or until there is nothing more to process.
Task.Wait and Task.WaitAll are the methods that stop this asynchronousness: the thread will really block until all async methods are completely finished.
There is seldom a reason to use Task.Run if you want to call an async method: simply call it, do not wait for it, so you can do other useful stuff. Make sure you Wait for the task to finish as soon as you need the result, or at the latest when you return the method.
Another method would be to return the tasks without waiting for them to finish, to give your caller the opportunity to do something useful as long as the tasks are not completed. Of course this can only be done if your procedure doesn't need the result of the task. It also obliges your caller to wait for completion, or pass the tasks to his caller.
The only reason to Task.Run that I can see, is that you want to start a lengthy procedure within your own process, that you don't want to wait for right now. Think of doing a lengthy calculations. Don't use Task.Run if another process is involved. In that case the other process should have an async function, or you should create an async extension method that does the task.Run.
int DoSomeLengthyCalculations(...) {...};
async Task<MyResult> CalculateIt(...)
{
Task<int> taskLengthyCalculations = Task.Run( () => DoSomeLengthyCalculations(...);
// if desired DoSomethingUsefull; after that wait for the task to end
// and process the result:
Task.Wait(taskLengthyCalculations);
int resultLengthyCalculations = taskLengthyCalucalations.Result();
MyResult result = ProcessResult(resultLengthyCalculations);
return result;
}
The nice thing is that you've hidden whether you are doing the lengthy calculations, or that someone else is doing it. For instance if you are unit testing methods that async access a database, you can mock this while accessing a Dictionary instead.
}
I have following line of code, to understand async-await and suspension till awaited task complete.
public async Task<string> WaitAsynchronouslyAsync()
{
var results = await WaitAsync();
Console.WriteLine($#"I am not waiting");
return results;
}
public async Task<string> WaitAsync()
{
await Task.Delay(10000).ConfigureAwait(false);
return "Async programming suspension point demo.";
}
The await operator suspends execution until the work of the WaitAsync() (Delay 10 seconds) method is complete.
In the meantime, I was expecting that Console.WriteLine($#"I am not waiting"); should write text to output window until awaited task completes, as control is returned to the caller of WaitAsync(). When the task finishes execution, the await expression evaluates string ("Async programming suspension point demo.").
Am I confused here with suspension pointer vs debug pointer?
The await operator suspends execution until the work of the WaitAsync() method is complete.
Correct.
I was expecting that Console.WriteLine($#"I am not waiting"); should write text to output window until awaited task completes, as control is returned to the caller of WaitAsync().
Why? You just said the await operator suspends execution until the work is complete. The work will not be complete for another ten seconds; the work is to wait for ten seconds. The work of WaitAsync is not complete until it executes the return, and that is in the future.
The right thing to do here is for WaitAsynchronouslyAsync to allow its caller an opportunity to run in this scenario.
You have correctly stated the meaning of await, but you seem to not be fully internalizing the consequences. An await checks its operand to see if the task is complete. If it is, then the result of the task is fetched and the method continues. If it is not, then the remainder of the method is signed up as the continuation of that task, and control is yielded so that more work can be done elsewhere. In the future, when the task completes, the remainder of the method is scheduled to execute.
await means "wait until this finishes executing asynchronously" your function will not continue until the supplied Task finishes executing.
If you instead said the following it wouldn't wait:
var results = WaitAsync();
Console.WriteLine($#"I am not waiting");
return await results;
Or even more succinctly, remove the async from the signature and then you can just return results;.
The sequence of operations will go something like this:
You call WaitAsynchronouslyAsync
WaitAsynchronouslyAsync calls WaitAsync
WaitAsync calls Task.Delay(10000).ConfigureAwait(false), which produces a Task.
WaitAsync returns a new Task to its caller, WaitAsynchronouslyAsync, which will be completed later
WaitAsynchronouslyAsync awaits the task from WaitAsync, and then returns to it's caller, providing a Task representing when it will be finished.
Other stuff happens further up the call stack.
Task.Delay finishes, so the continuation of WaitAsync fires, picking up where it left off.
WaitAsync returns the string, completing the Task.
WaitAsynchronouslyAsync can now continue, since the Task returned from WaitAsync has finished. It will go on to print out text to the console.
WaitAsynchronouslyAsync finishes it's task, letting anyone who has anything set up to run when it's finished to be able to run.
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.