-1

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?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
whd
  • 1,819
  • 1
  • 21
  • 52
  • 5
    Why isn't the "heavy stuff on a database" asynchronous? – juharr Feb 24 '21 at 20:06
  • edited question to avoid this kind of confusion – whd Feb 24 '21 at 20:46
  • 1
    @whd The point still stands. If the operation is spending time saving stuff to the DB, why are you not doing that asynchronously? – Servy Feb 24 '21 at 20:50
  • 1
    @Servy let say it is a method from a library which does not offer async methods. But in this case it is still valid question what is better `await SomeAsynMethod(); Task.Run(() => { SomeHeavyMethod();};` or `await SomeAsyncMethod().ConfigureAwait(false); SomeHeavyMethod();` – whd Feb 24 '21 at 20:58
  • 1
    The first approach is better IMHO. You can read my arguments in favor of `Task.Run` [here](https://stackoverflow.com/questions/38739403/await-task-run-vs-await/58306020#58306020). – Theodor Zoulias Feb 24 '21 at 21:08

1 Answers1

2

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.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • 2
    "At least in the general case." - yes. In particular, `HttpClient` on some mobile platforms may return (cached) results synchronously. – Stephen Cleary Feb 26 '21 at 12:48