Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens while waiting on a Task's Result?

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?

like image 925
scottt732 Avatar asked Sep 18 '12 19:09

scottt732


People also ask

Does task result wait?

Yes Accessing Task. Result is the same as calling Task. Wait(). Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.

How does task Wait work?

Wait is a synchronization method that causes the calling thread to wait until the current task has completed. If the current task has not started execution, the Wait method attempts to remove the task from the scheduler and execute it inline on the current thread.

Does await actually wait C#?

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.

How do I wait until task is finished in C#?

The Task. WaitAll() method in C# is used to wait for the completion of all the objects of the Task class. The Task class represents an asynchronous task in C#. We can start threads with the Task class and wait for the threads to finish with the Task.


2 Answers

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:

  1. If you block on a Task that is the result of an async method, you can easily get into a deadlock situation.
  2. 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).

like image 128
Stephen Cleary Avatar answered Sep 28 '22 17:09

Stephen Cleary


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.

like image 21
Atilla Baspinar Avatar answered Sep 28 '22 16:09

Atilla Baspinar