Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does waiting on Task.Result affect nested async/await methods?

Tags:

c#

async-await

This is a bit long winded, but here goes....

Given that I have an interface like so:

public interface IWebClientHelper
{
    TPayload Get<TPayload>(string url);
}

Where the implementation of Get makes a call to the supplied URL, which will return a response containing a Json object of type TPayload), and that Json is deserialized into TPayload and then returned.

I would like to make the implementation of the Get method asynchronous (or more specifically make the HTTP call contained within the Get method asynchronous), but as I understand it, that would require that the signature of the Get method be changed to:

Task<TPayload> Get<TPayload>(string url);

I am aiming to keep the interface as it is, so I created a second interface:

public interface IAsyncWebClientHelper
{
    Task<TPayload> Get<TPayload>(string url);
}

and injected that into my implementation of IWebClientHelper. So now my implementation of IWebClientHelper looks like this:

public TPayload Get<TPayload>(string url)
{
    return _asyncWebClientHelper.Get<TPayload>(url).Result;
}

and the Get method of _asyncWebClientHelper contains the line

message = await httpClient.GetAsync(url);

So what I am unclear on is this: Am I correct in thinking that the line return _asyncWebClientHelper.Get<TPayload>(url).Result will block the execution until that method returns? Or will the await keyword inside that method release the thread until it has received a response from the url?

like image 461
Chris Payne Avatar asked Sep 03 '13 15:09

Chris Payne


1 Answers

Yes, using Result means that your method will block. However, it's quite possible that means it will actually cause a deadlock. You haven't told us much about the context, but if you're in a context where after the await you need to return back to the same thread, but that thread is blocked due to the Result, you're basically deadlocking on yourself. You need to be very careful where you use any blocking calls such as the Result property or the Wait() method.

Fundamentally, trying to use asynchrony without making your interface asynchronous is tricky/pointless. You'd be much better off embracing asynchrony whole-heartedly, or sticking with the synchronous version. After all, if you're going to keep a thread blocked until the asynchronous task has completed, what's the benefit of the asynchrony in the first place?

like image 138
Jon Skeet Avatar answered Nov 08 '22 22:11

Jon Skeet