Do you have to await async methods? - c#

Lets say you have a service API call. The callee is somewhat performance critical, so in order not to hold up the API call any longer than necessary, there's an SaveAsync() method that is used. I can't await it, however, because that would hold up the API call just as long (or perhaps even longer) than the non-async version.
The reason I'm asking is this: If you don't await the call, is there a chance the Task object returned gets garbage collected? And if so, would that interrupt the running task?

The reason I'm asking is this: If you don't await the call, is there a chance the Task object returned gets garbage collected?
Generally, no, that shouldn't happen. The underlying TaskScheduler which queues the task, usually keeps a reference to it for the desired life-time until it completes. You can see that in the documentation of TaskScheduler.QueueTask:
A typical implementation would store the task in an internal data structure, which would be serviced by threads that would execute those tasks at some time in the future.
Your real problem is going to be with the ASP.NET SynchronizationContext, which keeps track of any on-going asynchronous operation at runtime. If your controller action finishes prior to the async operation, you're going to get an exception.
If you want to have "fire and forget" operations in ASP.NET, you should make sure to register them with the ASP.NET runtime, either via HostingEnvironment.QueueBackgroundWorkItem or BackgroundTaskManager

No, it won't interrupt the running task, but you won't observe the exceptions from the task either, which is not exactly good. You can (at least partially) avoid that by wrapping all running code in a try ... catch and log the exception.
Also, if you're inside asp.net, then your whole application could be stopped or recycled, and in this case your task will be interrupted. This is harder to avoid - you can register for AppPool shutdown notification, or use something like Hangfire.

Related

When exactly are synchronous continuations dangerous?

In a blog post, Microsoft's Sergey Tepliakov says:
you should always provide
TaskCreationOptions.RunContinuationsAsynchronously when creating
TaskCompletionSource instances.
But in that article, unless I misunderstood it, he also says that all await continuations basically act the same way as a TaskCompletionSource without TaskCreationOptions.RunContinuationsAsynchronously. So this would mean that async and await are also inherently dangerous and shouldn't be used, unless await Task.Yield() is used as well.
(edit: I did misunderstand it. He's saying that await continuing synchronously is the cause of the problematic SetResult behaviour. await Task.Yield() is recommended as a client-side workaround if the task creation can't be controlled at the source. Unless I misunderstood something again.)
I conclude that there must be specific circumstances that make synchronous continuations dangerous, and apparently that those circumstances are common for TaskCompletionSource use cases. What are those dangerous circumstances?
Thread theft, basically.
A good example here would be a client library that talks over the network to some server that is implemented as a sequence of frames on the same connection (http/2, for example, or RESP). For whatever reason, imagine that each call to the library returns a Task<T> (for some <T>) that has been provided by a TaskCompletionSource<T> that is awaiting results from the network server.
Now you want to write the read-loop that is dequeing responses from the server (presumably from a socket, stream, or pipeline API), resolve the corresponding TaskCompletionSource<T> (which could mean "the next in the queue", or could mean "use a unique correlation key/token that is present in the response").
So you effectively have:
while (communicationIsAlive)
{
var result = await ParseNextResultAsync(); // next message from the server
TaskCompletionSource<Foo> tcs = TryResolveCorrespondingPendingRequest(result);
tcs?.TrySetResult(result); // or possibly TrySetException, etc
}
Now; imagine that you didn't use RunContinuationsAsynchronously when you created the TaskCompletionSource<T>. The moment you do TrySetResult, the continuation executes on the current thread. This means that the await in some arbitrary client code (which can do anything) has now interrupted your IO read loop, and no other results will be processed until that thread relinquishes the thread.
Using RunContinuationsAsynchronously allows you to use TrySetResult (et al) without worrying about your thread being stolen.
(even worse: if you combine this with a subsequent sync-over-async call to the same resource, you can cause a hard deadlock)
Related question from before this flag existed: How can I prevent synchronous continuations on a Task?.

Proper way to start and fire-and-forget asynchronous calls?

I have an async call (DoAsyncWork()), that I would like to start in a fire-and-forget way, i.e. I'm not interesting in its result and would like the calling thread to continue even before the async method is finished.
What is the proper way to do this? I need this in both, .NET Framework 4.6 as well as .NET Core 2, in case there are differences.
public async Task<MyResult> DoWorkAsync(){...}
public void StarterA(){
Task.Run(() => DoWorkAsync());
}
public void StarterB(){
Task.Run(async () => await DoWorkAsync());
}
Is it one of those two or something different/better?
//edit: Ideally without any extra libraries.
What is the proper way to do this?
First, you need to decide whether you really want fire-and-forget. In my experience, about 90% of people who ask for this actually don't want fire-and-forget; they want a background processing service.
Specifically, fire-and-forget means:
You don't care when the action completes.
You don't care if there are any exceptions when executing the action.
You don't care if the action completes at all.
So the real-world use cases for fire-and-forget are astoundingly small. An action like updating a server-side cache would be OK. Sending emails, generating documents, or anything business related is not OK, because you would (1) want the action to be completed, and (2) get notified if the action had an error.
The vast majority of the time, people don't want fire-and-forget at all; they want a background processing service. The proper way to build one of those is to add a reliable queue (e.g., Azure Queue / Amazon SQS, or even a database), and have an independent background process (e.g., Azure Function / Amazon Lambda / .NET Core BackgroundService / Win32 service) processing that queue. This is essentially what Hangfire provides (using a database for a queue, and running the background process in-proc in the ASP.NET process).
Is it one of those two or something different/better?
In the general case, there's a number of small behavior differences when eliding async and await. It's not something you would want to do "by default".
However, in this specific case - where the async lambda is only calling a single method - eliding async and await is fine.
It depends on what you mean by proper :)
For instance: are you interested in the exceptions being thrown in your "fire and forget" calls? If not, than this is sort of fine. Though what you might need to think about is in what environment the task lives.
For instance, if this is a asp.net application and you do this inside the lifetime of a thread instantiated due to a call to a .aspx or .svc. The Task becomes a background thread of that (foreground)thread. The foreground thread might get cleaned up by the application pool before your "fire and forget" task is completed.
So also think about in which thread your tasks live.
I think this article gives you some useful information on that:
https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
Also note that if you do not return a value in your Tasks, a task will not return exception info. Source for that is the ref book for microsoft exam 70-483
There is probably a free version of that online somewhere ;P https://www.amazon.com/Exam-Ref-70-483-Programming-C/dp/0735676828
Maybe useful to know is that if your have an async method being called by a non-async and you wish to know its result. You can use .GetAwaiter().GetResult().
Also I think it is important to note the difference between async and multi-threading.
Async is only useful if there are operations that use other parts of a computer that is not the CPU. So things like networking or I/O operations. Using async then tells the system to go ahead and use CPU power somewhere else instead of "blocking" that thread in the CPU for just waiting for a response.
multi-threading is the allocation of operations on different threads in a CPU (for instance, creating a task which creates a background thread of the foreground thread... foreground threads being the threads that make up your application, they are primary, background threads exist linked to foreground threads. If you close the linked foreground thread, the background thread closes as well)
This allows the CPU to work on different tasks at the same time.
Combining these two makes sure the CPU does not get blocked up on just 4 threads if it is a 4 thread CPU. But can open more while it waits for async tasks that are waiting for I/O operations.
I hope this gives your the information needed to do, what ever it is you are doing :)

What happens with a non-awaited asynch method call upon async completion?

I have an asynchronous method in which I wish to invoke the SendAsync method as a fire-and-forget service. Consider the following code:
public async Task HandleAsync(DoStuffCommand command)
{
/*
* Performing various tasks..
*/
_client.SendAsync(myObject);
}
public async Task SendAsync(MyObject myObject)
{
/*
* Time consuming tasks..
*/
try
{
await call_1();
Trace.TraceInformation("Call1");
await call_2();
Trace.TraceInformation("Call2");
}
catch (Exception e)
{
Trace.TraceError(e.Message);
throw;
}
}
My problem is that for some reason call_2 is inconsistently getting called (very rarely). My suspicion is that the SendAsync method is not allowed to complete because the calling method HandleAsync does not await SendAsync and when the HandleAsync thread is terminated, the work in progress in SendAsync is too.
But, this is contrary to my understanding of async/await. I was under the impression that the SendAsync implementation would perform its work on a different thread in this scenario, and thus, be able to complete even if HandleAsync would return before SendAsync.
Maybe someone more async/await than myself can shed some light? Thank you.
UPDATE
I also tried adding a try/catch and traces. No exceptions are thrown but the trace consistently follows the behavior of the method calls, i.e. When both calls are made, so are both TraceInformation and when only call_1 is invoked, only the first TraceInformation runs.
I have an asynchronous method in which I wish to invoke the SendAsync method as a fire-and-forget service.
As I describe on my blog, fire-and-forget on ASP.NET is inherently dangerous and almost always the wrong solution to whatever requirement you're trying to meet. One of the main problems with "fire and forget" is that the background work is forgotten. There will always be some situations (hopefully rare) where the background work does not run, or is silently dropped. The only way to prevent this loss of work is to implement a reliable distributed system architecture.
My suspicion is that the SendAsync method is not allowed to complete because the calling method HandleAsync does not await SendAsync and when the HandleAsync thread is terminated, the work in progress in SendAsync is too.
ASP.NET is less about threads than it is about request contexts. When HandleAsync completes, the request context for that request is disposed, and that may cause some code in SendAsync to fail or behave erratically.
I was under the impression that the SendAsync implementation would perform its work on a different thread in this scenario, and thus, be able to complete even if HandleAsync would return before SendAsync.
No, absolutely not. async does not mean "run on another thread". If you want to run on another thread, then you have to do so explicitly (e.g., Task.Run). However, this is almost always a bad idea on ASP.NET.
If you want to minimize the loss of work, then use HostingEnvironment.QueueBackgroundWorkItem; if you want to prevent the loss of work, then either reject the fire-and-forget requirement or implement a proper distributed architecture. A proper distributed architecture is one with a reliable message queue (such as Azure Queues or MSMQ) with an independent worker process (such as Azure Functions or Win32 Services).

Web API Sync Calls Best Practice

Probably this question has already been made, but I never found a definitive answer. Let's say that I have a Web API 2.0 Application hosted on IIS. I think I understand that best practice (to prevent deadlocks on client) is always use async methods from the GUI event to the HttpClient calls. And this is good and it works. But what is the best practice in case I had client application that does not have a GUI (e.g. Window Service, Console Application) but only synchronous methods from which to make the call? In this case, I use the following logic:
void MySyncMethodOnMyWindowServiceApp()
{
list = GetDataAsync().Result().ToObject<List<MyClass>>();
}
async Task<Jarray> GetDataAsync()
{
list = await Client.GetAsync(<...>).ConfigureAwait(false);
return await response.Content.ReadAsAsync<JArray>().ConfigureAwait(false);
}
But unfortunately this can still cause deadlocks on client that occur at random times on random machines.
The client app stops at this point and never returns:
list = await Client.GetAsync(<...>).ConfigureAwait(false);
If it's something that can be run in the background and isn't forced to be synchronous, try wrapping the code (that calls the async method) in a Task.Run(). I'm not sure that'll solve a "deadlock" problem (if it's something out of sync, that's another issue), but if you want to benefit from async/await, if you don't have async all the way down, I'm not sure there's a benefit unless you run it in a background thread. I had a case where adding Task.Run() in a few places (in my case, from an MVC controller which I changed to be async) and calling async methods not only improved performance slightly, but it improved reliability (not sure that it was a "deadlock" but seemed like something similar) under heavier load.
You will find that using Task.Run() is regarded by some as a bad way to do it, but I really couldn't see a better way to do it in my situation, and it really did seem to be an improvement. Perhaps this is one of those things where there's the ideal way to do it vs. the way to make it work in the imperfect situation that you're in. :-)
[Updated due to requests for code]
So, as someone else posted, you should do "async all the way down". In my case, my data wasn't async, but my UI was. So, I went async down as far as I could, then I wrapped my data calls with Task.Run in such as way that it made sense. That's the trick, I think, to figure out if it makes sense that things can run in parallel, otherwise, you're just being synchronous (if you use async and immediately resolve it, forcing it to wait for the answer). I had a number of reads that I could perform in parallel.
In the above example, I think you have to async up as far as makes sense, and then at some point, determine where you can spin off a t hread and perform the operation independent of the other code. Let's say you have an operation that saves data, but you don't really need to wait for a response -- you're saving it and you're done. The only thing you might have to watch out for is not to close the program without waiting for that thread/task to finish. Where it makes sense in your code is up to you.
Syntax is pretty easy. I took existing code, changed the controller to an async returning a Task of my class that was formerly being returned.
var myTask = Task.Run(() =>
{
//...some code that can run independently.... In my case, loading data
});
// ...other code that can run at the same time as the above....
await Task.WhenAll(myTask, otherTask);
//..or...
await myTask;
//At this point, the result is available from the task
myDataValue = myTask.Result;
See MSDN for probably better examples:
https://msdn.microsoft.com/en-us/library/hh195051(v=vs.110).aspx
[Update 2, more relevant for the original question]
Let's say that your data read is an async method.
private async Task<MyClass> Read()
You can call it, save the task, and await on it when ready:
var runTask = Read();
//... do other code that can run in parallel
await runTask;
So, for this purpose, calling async code, which is what the original poster is requesting, I don't think you need Task.Run(), although I don't think you can use "await" unless you're an async method -- you'll need an alternate syntax for Wait.
The trick is that without having some code to run in parallel, there's little point in it, so thinking about multi-threading is still the point.
Using Task<T>.Result is the equivalent of Wait which will perform a synchronous block on the thread. Having async methods on the WebApi and then having all the callers synchronously blocking them effectively makes the WebApi method synchronous. Under load you will deadlock if the number of simultaneous Waits exceeds the server/app thread pool.
So remember the rule of thumb "async all the way down". You want the long running task (getting a collection of List) to be async. If the calling method must be sync you want to make that conversion from async to sync (using either Result or Wait) as close to the "ground" as possible. Keep they long running process async and have the sync portion as short as possible. That will greatly reduce the length of time that threads are blocked.
So for example you can do something like this.
void MySyncMethodOnMyWindowServiceApp()
{
List<MyClass> myClasses = GetMyClassCollectionAsync().Result;
}
Task<List<MyClass>> GetMyListCollectionAsync()
{
var data = await GetDataAsync(); // <- long running call to remote WebApi?
return data.ToObject<List<MyClass>>();
}
The key part is the long running task remains async and not blocked because await is used.
Also don't confuse the responsiveness with scalability. Both are valid reasons for async. Yes responsiveness is a reason for using async (to avoid blocking on the UI thread). You are correct this wouldn't apply to a back end service however this isn't why async is used on a WebApi. The WebApi is also a non GUI back end process. If the only advantage of async code was responsiveness of the UI layer then WebApi would be sync code from start to finish. The other reason for using async is scalability (avoiding deadlocks) and this is the reason why WebApi calls are plumbed async. Keeping the long running processes async helps IIS make more efficient use of a limited number of threads. By default there are only 12 worker threads per core. This can be raised but that isn't a magic bullet either as threads are relatively expensive (about 1MB overhead per thread). await allows you to do more with less. More concurrent long running processes on less threads before a deadlock occurs.
The problem you are having with deadlocks must stem from something else. Your use of ConfigureAwait(false) prevents deadlocks here. Solve the bug and you are fine.
See Should we switch to use async I/O by default? to which the answer is "no". You should decide on a case by case basis and choose async when the benefits outweigh the costs. It is important to understand that async IO has a productivity cost associated with it. In non-GUI scenarios only a few targeted scenarios derive any benefit at all from async IO. The benefits can be enormous, though, but only in those cases.
Here's another helpful post: https://stackoverflow.com/a/25087273/122718

What are the implications for incomplete async tasks in .NET 4.5?

Suppose you have a web handler that calls an asynchronous method like such:
var foo = await SomeMethod();
And, due to poor coding (no CancellationToken, no timeouts, etc), SomeMethod never completes. The frustrated user, in turn, presses "stop" on her browser and goes to the pub.
Suppose this happens to a lot of users.
I know that I can write a timeout to prevent it from waiting eternally, but if I do not... what happens? Is this a memory leak? Does it get cleaned up eventually? What's the worst-case scenario?
And SomeMethod never returns. The user cancels the request and goes to the pub.
Those are not the same thing, at all.
If SomeMethod never completes, then you have a memory leak. You should never, ever, ever write code that does this.
OTOH, if the user cancels the request (cancelling a CancellationToken), then the method will complete, possibly with an OperationCanceledException.
It depends on the implementation of the Task returned by SomeMethod. The task is responsible for calling the continuation (ContinueWith), which will move execution forward. If the task never continued, you would have a memory leak. Most asynchronous APIs provide a timeout which would prevent this situation.

Categories