What happens while waiting on a Task's Result? - c#

I'm using the HttpClient to post data to a remote service in a .NET 4.0 project. I'm not concerned with this operation blocking, so I figured I could skip ContinueWith or async/await and use Result.
While debugging, I ran into an issue where the remote server wasn't responsive. As I stepped through the code, it seemed like my code just stopped running on the third line... the current stack pointer line stopped being highlighted yellow, and didn't advance to the next line. It just disappeared. It took me a while to realize that I should wait for the request to timeout.
var client = new HttpClient();
var task = client.PostAsync("http://someservice/", someContent);
var response = task.Result;
My understanding was that calling Result on the Task caused the code to execute synchronously, to behave more like this (I know there is no Post method in the HttpClient):
var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);
I'm not sure this is a bad thing, I'm just trying to get my head around it. Is it really true that by virtue of the fact that the HttpClient is returning Tasks instead of the results directly, my application is automatically taking advantage of asynchrony even when I think I'm avoiding it?

In Windows, all I/O is asynchronous. Synchronous APIs are just a convenient abstraction.
So, when you use HttpWebRequest.GetResponse, what actually happens is the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.
Similarly, when you use HttpClient.PostAsync(..).Result, the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.
I usually recommend people use await rather than Task.Result or Task.Wait for the following reasons:
If you block on a Task that is the result of an async method, you can easily get into a deadlock situation.
Task.Result and Task.Wait wrap any exceptions in an AggregateException (because those APIs are holdovers from the TPL). So error handling is more complex.
However, if you're aware of these limitations, there are some situations where blocking on a Task can be useful (e.g., in a Console application's Main).

Capturing the result of a task blocks the current thread. There is no point in using a async version of a method in this case. Post() and PostAsync().Result will both block.
If you want to make use of concurrency, you should write it as such:
async Task PostContent()
{
var client = new HttpClient();
Task t = await client.PostAsync("http://someservice/", someContent);
//code after this line will execute when the PostAsync completes.
return t;
}
Since PostContent() itself returns a Task, the method calling it should also await.
async void ProcessResult()
{
var result = await PostContent();
//Do work with the result when the result is ready
}
For instance, if you call ProcessResult() in a button click handler, you see that the UI is still responsive, other controls still function.

Related

Use ConfigureAwait(false) or Task.Run to avoid blocking UI Thread

I'm trying to find out which approach is better let's say we have a button, after user clicks it we perform 1. Send a async request using httpClient
2. Some heavy synchronous staff like computations and saving data to a database.
Like that:
button1.Click += async(sender, e) =>
{
bool a = await Task.Run(async () => { return await MyTask1();});
}
async Task<bool> MyTask1()
{
await new HttpClient().GetAsync("https://www.webpage.com");
DoHeavyStuffFor5minutes();
return true;
}
button2.Click += async(sender, e) =>
{
bool a = await MyTask2();
}
async Task<bool> MyTask2()
{
await new HttpClient().GetAsync("https://www.webpage.com").ConfigureAwait(false);
DoHeavyStuffFor5minutes();
}
From what i understand GetAsync does not block my UI thread because underneath it uses a method which make it runs on different thread perhaps Task.Run or any other method that allows that.
But DoHeavyStuffFor5Minutes will block my UI because it will get called on the caller SynchornizationContext.
So i read that using ConfigureAwait(false) will make code after GetAsync do not run on the same SynchornizationContext as the caller. My question is, which approach is better first or the second one?
There is no need to execute HttpClient.GetAsync on a background thread using Task.Run since the HTTP request is truly asynchronous by nature so in this case your second approach is better that the first one.
When the Task returned by GetAsync has eventually finished, the remainder or MyTask2() will be executed on a thread pool thread assuming you opt out of capturing the context by calling ConfigureAwait(false).
Note however that ConfigureAwait(false) does not guarantee that the callback or remainer won't be run in the original context in all cases.
From Stephen Toub's blog post:
Does ConfigureAwait(false) guarantee the callback won’t be run in the original context?
"No. It guarantees it won’t be queued back to the original contex...but that doesn’t mean the code after an await task.ConfigureAwait(false) won’t still run in the original context. That’s because awaits on already-completed awaitables just keep running past the await synchronously rather than forcing anything to be queued back. So, if you await a task that’s already completed by the time it’s awaited, regardless of whether you used ConfigureAwait(false), the code immediately after this will continue to execute on the current thread in whatever context is still current."
So you might want to off-load DoHeavysTuffFor5minutes, which I assume is a CPU-bound and potentially long-running operation, to a background thread using Task.Run to be on the safe side. At least in the general case.
Also note that a method that is named *Async and returns a Task or Task<T> might still block the calling thread depending on its implementation. In general, this may be a reason to use your first approach of a calling both methods on a background thread in order to avoid blocking the UI thread. If you however use well-implemented APIs, such as HttpClient, this isn't an issue though.

Background started task does not finish/gets terminated after the first encountered await

In an ASP.NET application, I have an action which when hit, starts a new background task in the following way:
Task.Factory.StartNew(async () => await somethingWithCpuAndIo(input), CancellationToken.None, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());
I'm not awaiting it, I just want it to start, and continuing doing its work in the background.
Immediately after that, I return a response to the client.
For some reason though, after the initial thread executing the background work hits an await that awaits the completion of a method, when debugging, I successfully resolve the method, but upon returning, execution just stops and does not continue below that point.
Interestingly, if I fully await this task (using double await), everything works as expected.
Is this due to the SynchronizationContext? The moment I return a response, the synchronizationContext is disposed/removed? (The SynchronizationContext is being used inside the method)
If it is due to that, where exactly does the issue happen?
A) When the Scheduler attempts to assign the work on the given synchronizationContext, it will already be disposed, so nothing will be provided
B) Somewhere down the lines in the method executing, when I return a response to the client, the synchronizationContext is lost, regardless of anything else.
C) Something else entirely?
If it's A), I should be able to fix this by simply doing Thread.Sleep() between scheduling the work and returning a response. (Tried that, it didn't work.)
If it's B) I have no idea how I can resolve this. Help will be appreciated.
As Gabriel Luci has pointed out, it is due the the first awaited incomplete Task returning immediately, but there's a wider point to be made about Task.Factory.StartNew.
Task.Factory.StartNew should not be used with async code, and neither should TaskCreationOptions.LongRunning. TaskCreationOptions.LongRunning should be used for scheduling long running CPU-bound work. With an async method, it may be logically long running, but Task.Factory.StartNew is about starting synchronous work, the synchronous part of an async method is the bit before the first await, this is usually very short.
Here is the guidance from David Fowler (Partner Software Architect at Microsoft on the ASP.NET team) on the matter:
https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/86b502e88c752e42f68229afb9f1ac58b9d1fef7/AsyncGuidance.md#avoid-using-taskrun-for-long-running-work-that-blocks-the-thread
See the 3rd bulb:
Don't use TaskCreationOptions.LongRunning with async code as this will
create a new thread which will be destroyed after first await.
Your comments made you intentions a little clearer. What I think you want to do is:
Start the task and don't wait for it. Return a response to the client before the background task completes.
Make sure that the somethingWithCpuAndIo method has access to the request context.
But,
A different thread won't be in the same context, and
As soon as the first await is hit, a Task is returned, which also means that Task.Factory.StartNew returns and execution of the calling method continues. That means that the response is returned to the client. When the request completes, the context is disposed.
So you can't really do both things you want. There are a couple of ways to work around this:
First, you might be able to not start it on a different thread at all. This depends on when somethingWithCpuAndIo needs access to the context. If it only needs the context before the first await, then you can do something like this:
public IActionResult MyAction(input) {
somethingWithCpuAndIo(input); //no await
}
private async Task somethingWithCpuAndIo(SomeThing input) {
// You can read from the request context here
await SomeIoRequest().ConfigureAwait(false);
// Everything after here will run on a ThreadPool thread with no access
// to the request context.
}
Every asynchronous method starts running synchronously. The magic happens when await is given an incomplete Task. So in this example, somethingWithCpuAndIo will start executing on the same thread, in the request context. When it hits the await, a Task is returned to MyAction, but it is not awaited, so MyAction completes executing and a response gets sent to the client before SomeIoRequest() has completed. But ConfigureAwait(false) tells it that we don't need to resume execution in the same context, so somethingWithCpuAndIo resume execution on a ThreadPool thread.
But that will only help you if you don't need the context after the first await in somethingWithCpuAndIo.
Your best option is to still execute on a different thread, but pass the values you need from the context into somethingWithCpuAndIo.
But also, use Task.Run instead of Task.Factory.StartNew for reasons described in detail here.
Update: This can very likely cause unpredictable results, but you can also try passing a reference to HttpContext.Current to the thread and setting HttpContext.Current in the new thread, like this:
var ctx = HttpContext.Current;
Task.Run(async () => {
HttpContext.Current = ctx;
await SomeIoRequest();
});
However, it all depends on how you are using the context. HttpContext itself doesn't implement IDiposable, so it, itself, can't be disposed. And the garbage collector won't get rid of it as long as you're holding a reference to it. But the context isn't designed to live longer than the request. So after the response is returned to the client, there may be many parts of the context that are disposed or otherwise unavailable. Test it out an see what explodes. But even if nothing explodes right now, you (or someone else) might come back to that code later, try to use something else in the context and get really confused when it blows up. It could make for some difficult-to-debug scenarios.

What's the difference between using .Result inside a Task body and using await in async method?

I managed to find some answers to similar questions posted around the internet, but no one of them explained it satisfying enough to make me understand the difference in the code below.
I am aware that await, unlike .Result, doesn't block calling thread. But what if we're trying to access this property from a task, which doesn't block it anyway?
For instance, is there any difference between this
public static Task PrintPageAsync(string url)
{
return Task.Run(() =>
{
WebRequest webRequest = WebRequest.Create(url);
WebResponse response = webRequest.GetResponseAsync().Result;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string text = reader.ReadToEndAsync().Result;
Console.WriteLine(text);
}
});
}
and this
public static async Task PrintPageAsync(string url)
{
WebRequest webRequest = WebRequest.Create(url);
WebResponse response = await webRequest.GetResponseAsync();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string text = await reader.ReadToEndAsync();
Console.WriteLine(text);
}
}
.Result will execute your code synchronously, i.e. you're disregarding the very essence of the Task and entire TPL standing behind it. await, as it says, is a marker for the compiler to rewrite your method in a good-old "callback" fashion (a-ka typical JavaScript), which is asynchronous way to complete exactly the same computation.
Simpler: you should prefer await over .Result whenever possible.
Since the first example starts a new task on a threadpool thread, calling asynchronous methods is unnecessary, when there are equivalent synchronous methods. It does not have any benefit, it just needlessly add some overhead involved in managing asynchronous tasks. Just use .GetResponse() instead of .GetResponseAsync().Result and .ReadToEnd() instead of .ReadToEndAsync().Result.
await, unlike .Result, doesn't block calling thread
This is not always true. Awaited methods can execute (partially or completely) synchronously, if they decide to do so.
For instance, is there any difference?
There are a bunch of differences between the two examples. Although they may be insignificant in certain contexts, they can be crucial in another:
AggregateException
When exception occurs in a task or task is cancelled, calling Task.Result will wrap exception in an AggregateException. Contrary, awaiting this task will throw the original exception. So you must be careful when catching specific exception.
Thread
In the first example, whole method will execute on the same (threadpool) thread. The second example can execute on several different threads, depending on the current SynchronizationContext. Code sensitive to thread-affinity should be avoided.
SynchronizationContext
First exapmple will execute without SynchronizationContext, while the second will restore original SynchronizationContext after each await. For console applications, this doesn't matter. But in WPF or WinForms applications, UI elements can be accessed only from corresponding synchronization context.
Asynchronous execution
In the first example, PrintPageAsync will return immediatelly after new task is queued for execution, while the second will execute synchronously up to the first await (or possibly even after that). This can have severe impact on GUI responsivnes, especially when async method uses WebRequest, because GetResponseAsync() method performs DNS resolution synchronously (see How to create HttpWebRequest without interrupting async/await?). So wrapping code in a Task.Run() is recomended, when method that uses WebRequest is called from UI thread.

Why doesn't this call to .Result provoke a deadlock?

I'm still trying to wrap my head around when I can use .Result, and when I can't. I have been trying to avoid it entirely, by using async "all the way down".
While doing some work in our ASP.NET web app (NOT core), I came across this code. Now, the code works (and has been working for 2 years), so I know it works, I just don't know why it works.
This is fired from a sync controller method. It is a chain of method calls that goes through a few layers until it finally does some HTTP work. I have simplified the code here:
// Class1
public byte[] GetDocument1(string url)
{
return class2.GetDocument2(url).Result;
}
// Class2
public Task<byte[]> GetDocument2(string url)
{
return class3.GetDocument3(url)
}
// Class3
public async Task<byte[]> GetDocument3(string url)
{
var client = GetHttpClient(url);
var resp = client.GetAsync(url).Result;
if(resp.StatusCode == HttpStatusCode.OK)
{
using(var httpStream = await resp.Content.ReadAsStreamAsync())
{
// we are also using
await httpStream.ReadAsync(...);
}
}
}
So as far as I can tell, when this all starts, I'm on the "main ASP sync context" (I start in a controller and eventually get to this code). We aren't using any .ConfigureAwait(false), so I believe we are always returning to this context.
In GetDocument3, why doesn't client.GetAsync(url).Result deadlock?
GetDocument3 is mixing .Result with await stuff. In general, is that a good idea?? Is it OK here because .Result comes before the awaits?
In GetDocument1, why doesn't .Result deadlock?
client.GetAsync(url).Result is synchronously blocking. resp.Content.ReadAsStreamAsync() is actually not doing any awaiting. The Task is already completed, because HttpCompletionOption.ResponseContentRead is used in GetAsync, so the entire block of code here is synchronous code pretending to be asynchronous.
In general, you should never use .Result or .Wait or Task.Wait* - if you absolutely have to, use GetAwaiter().GetResult(), which doesn't throw exceptions wrapped in AggregateExceptions, for which you may not have a catch, but even that should be avoided like the plague. You're right to use async all the way down.
The deadlock is only a problem in a context that wants to return back to the original thread (e.g. UI or ASP.NET), and that thread is blocked by a synchronous wait. If you always use ConfigureAwait(false) on every await, unless you know you actually need to preserve the context on the continuation (usually only at the top level UI event handler because you need to update something on the UI, or in the top level of the ASP.NET controller) then you should be safe.
Synchronous blocking inside asynchronous code also isn't good, but won't cause the deadlock. Using await with ConfigureAwait(true) (the default), inside a synchronous wait, in a context that wants to return back to a specific thread will cause the deadlock.

WCF Service Client with .NET 4.5 Task-Based Async Operations, await never returns

I've added a WCF service reference to my .NET 4.5 app, using the default "Generate task-based operations" option under "Allow Generation of asynchronous operations." I'm calling the service from an async method of my own, sort of like so:
public async Task<SomeData> GetDataAsync()
{
var client = new MyServiceClient();
var result = await client.GetSomeDataAsync();
return result;
}
The await client.GetSomeDataAsync() never completes (a breakpoint on the return statement never gets hit) and I don't get a time out or any other error, no exception is thrown, nothing. Fiddler shows that the client sent the request and the service responded almost instantly with the expected data, so the problem is on my side of the fence somehow.
If I switch to the synchronous version instead
var result = client.GetSomeData();
The call returns as expected.
What am I doing wrong?
My chest hairs are tingling, Mr. T. I strongly suspect that further up your (client-side) call stack, you have some code that is calling Task<T>.Result or Task.Wait, which significantly increases the possibility of a deadlock (as I explain on my blog).
By default, when you await a Task, the await will capture a "context" and use that to resume the async method. If this is a context like a UI thread context, and then the code blocks the UI thread (i.e., calling Result or Wait), then the async method cannot resume on that UI thread.
I pity the fool who would attempt to mix synchronous and asynchronous code. Just use async all the way (as I describe in an MSDN article).

Categories