0

I have a method void getInformation() that calls 5 other methods of which each is getting some data from a database. It takes about 1 second until all data is collected and returned to getInformation() and because of that I thought I should collect the data in the background. My question is: can I just make getInformation() async so the UI isn't blocked while the other methods are collecting the information or do I have to make every of the other methods async ?

private void button_Click(object sender, EventArgs e)
{
  await getContactInformation();
}

public async Task getContactInformation()
{
  this.data.Add(collectData1());
  this.data.Add(collectData2());
  this.data.Add(collectData3());
  this.data.Add(collectData4());
  this.data.Add(collectData5());
}
Daniel Kelley
  • 7,579
  • 6
  • 42
  • 50
user2414460
  • 211
  • 3
  • 14
  • look into this [tutorial](http://www.dotnetperls.com/async) – Sagar Pilkhwal Sep 11 '14 at 10:37
  • 1
    Take a look at these Q&As: https://stackoverflow.com/questions/14177891/can-somebody-please-explain-async-await, https://stackoverflow.com/questions/10960998/how-different-async-programming-is-from-threads and https://stackoverflow.com/questions/14455293/async-and-await – Dirk Sep 11 '14 at 10:43

4 Answers4

2

In general I would recommend all IO to be taken off the UI thread, but there is no point in making each individual call async.

For guidance on the effect of async calls on database IO blocked threads, I found this very clear and useful advice.

http://blogs.msdn.com/b/rickandy/archive/2009/11/14/should-my-database-calls-be-asynchronous.aspx

AlexanderBrevig
  • 1,967
  • 12
  • 17
PhillipH
  • 6,182
  • 1
  • 15
  • 25
2

No. Your method body has to use an await or you'll get a warning.

Easy enough.

Wrap your method body with...

await Task.Run(()=>{
// do your thing
});
Daniel Kelley
  • 7,579
  • 6
  • 42
  • 50
kidshaw
  • 3,423
  • 2
  • 16
  • 28
2

First off, the ideal situation for async is to use "async all the way". In this case, your code would look like this:

private async void button_Click(object sender, EventArgs e)
{
  await getContactInformationAsync();
}

public async Task getContactInformationAsync()
{
  this.data.Add(await collectData1Async());
  this.data.Add(await collectData2Async());
  this.data.Add(await collectData3Async());
  this.data.Add(await collectData4Async());
  this.data.Add(await collectData5Async());
}

Note that modern database APIs such as Entity Framework 6, ADO.NET, SQLite, etc, all have asynchronous APIs that you can use to implement the collectDataNAsync methods. This is the ideal async scenario, since it minimizes thread waste and also keeps the UI nicely responsive.

However, if you want more of a "quick fix", then you can push the (synchronous) calls off to a background thread, and then treat that background work asynchronously, as such:

private async void button_Click(object sender, EventArgs e)
{
  await Task.Run(() => getContactInformation());
}

public void getContactInformation()
{
  this.data.Add(collectData1());
  this.data.Add(collectData2());
  this.data.Add(collectData3());
  this.data.Add(collectData4());
  this.data.Add(collectData5());
}

This would solve your immediate problem (freeing up the UI thread) at the expense of a thread pool thread. It's not ideal but it would work.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

can I just make getInformation() async so the UI isn't blocked while the other methods are collecting the information or do I have to make every of the other methods async ?

The latter. When you go async it is "async all the way", meaning you make async method calls all the way to the top of your stack. For IO bound operations, there isn't a need to use background threads, since most APIs these days expose XXXAsync method calls which are truely asynchronous, which means your UI message loop is free to process other messages while the IO request executes.

An important thing to note though is that marking a method async is not enough to make it asynchronous. You actually have to await an async operation, such as your database method call. If there's no async API call to your database, you wont be able to go async.

In you case, getContactInformation will make the compiler omit a warning saying you have an async method which isn't being awaited. De-Facto, if you await getInformation(), you will be running completely synchronously.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • But if I want to make the data-collect-calls `async` too, I'd have to change my whole project. This code was just to get an idea on how to get a solution for this – user2414460 Sep 11 '14 at 12:05
  • The solution is to make your data-collect calls `async`. That is the primary point. If your DB calls are synchronous, how do you expect to make them async? – Yuval Itzchakov Sep 11 '14 at 12:21
  • I was hoping for a solution where I don't have to change all method- bodys and headers, something like `BackgroundClass.doInBackground(methodCall)`, that makes the UI responsive but still executes the called method. – user2414460 Sep 11 '14 at 12:26
  • You *can* do this using a background thread. But, that would be waisting a completely good thread which will simply block until the IO request completes. If you need this to scale-out eventually, that wont work. I would recommend you not to do that. I think it is worth the effort to refactor your codebase to support true asynchronous calls. – Yuval Itzchakov Sep 11 '14 at 12:28