StackMan
StackMan

Reputation: 55

How to make an async httpclient web *response* to be handled until later (after calculations)

I make a httpclient call then want to start calculations imediatly. I don't want the calculations disturbed by the returning response. The calculations can take up to 3 seconds.

pseudo-ish code

{
    var data = await GetDataFromCloud();

    //do calculations - highly time sensitive!
    DoCalc() //A recursive job or nested loop *the response is occurring within this call :(

    //I want the response to occur here after the work above has completed :)

}

Would lock work here. This code is inside an asynchronous function on the UI thread. DoCalc is made non blocking. The UI thread is not blocked.

Upvotes: 1

Views: 67

Answers (2)

Harald Coppoolse
Harald Coppoolse

Reputation: 30512

This is exactly a scenario where we'd like to want to use async-await!

Async-await is useful when your thread has to wait idly for something else to complete. For example, a file to be read, a database query to be performed, a web-page to be downloaded. Typically scenarios where someone else is doing the work, while your thread is just waiting for the work to complete.

Functions where you can "do something else instead of idly waiting" are declared async. See Stream.ReadAsync when reading files, Dapper.SQLMapper.QueryAsync when performing database queries, ToListAsync and FirstOrDefaultAsync for database queries in entity-framework, WebClient.DownloadFileAsync for internet downloads etc.

If you call an async function, the return value is a Task instead of void, or a Task<TResult> instead of TResult. There is one exception: event handlers don't result a Task but void.

If you want to benefit from async-await you have to define your function async and return a Task or Task<TResult>

When you call an async function, you may be certain that somewhere in this function is an await. In fact, your compiler will warn you if you forget to await somewhere. Similarly you get a warning if you define your function async but forget to call another async function

After you've called the other async function you can continue working as long as you don't need the results from the call. As soon as you need the results you await the task.

If you start to await the task, and the data is still not available, then your thread will go up its call stack to see if your caller has something to do until your caller's await. Up the call stack again to see if there is work to do, etc.

async Task<MyResult> GetMyData(...)
{
    Task<SomeData> taskGetData = GetDataFromCloud(...);

     // while the data is being fetched, we can continue working
     DoSomethingElse();

     // now we need the data:
     SomeData fetchedData = await taskGetData;
     MyResult result = ProcessFetchedData(fetchedData);
     return result;
}

What helped me to understand async-await is this interview with Eric Lippert. Search somewhere in the middle for async-await.

What also helped me was this article by the ever so helpful Stephen Cleary

Upvotes: 0

Scott Perham
Scott Perham

Reputation: 2470

Assuming that you don't need the data returned form GetDataFromCloud() to actually perform the calculations, you can grab the Task from the method rather than awaiting it, do your calculations and then await it afterwards.

Something like this:

{
    var dataTask = GetDataFromCloud(); // Starts the task and returns it

    //do calculations - highly time sensitive!
    DoCalc()

    var data = await dataTask; // Wait for the task to finish (if it hasn't already)
}

Of course, if the data is required for the calculations then you either need to wait for it all to be downloaded first or handle a "stream" of data by grabbing the HttpResponseMessage and reading the content manually.

EDIT:

It's also worth noting that if something were to go wrong in the request (i.e. an exception is thrown), using this approach you won't know about it until the await.

Upvotes: 2

Related Questions