patterncsharpCritical
When correctly use Task.Run and when just async-await
Viewed 0 times
runjustandawaituseasyncwhencorrectlytask
Problem
I would like to ask you on your opinion about the correct architecture when to use
application (with Caliburn Micro framework).
Basically I am doing (very simplified code snippets):
From the articles/videos I read/saw, I know that
Where is the best place to put Task.Run?
Should I just
-
Wrap the outer call because this is less threading work for .NET
-
, or should I wrap only CPU-bound methods internally running with
Ad (1), the first solution would be like this:
Ad (2), the second solution would be like this:
```
public async Task DoCpuBoundWorkAsync()
{
await Task.Run(() => {
Task.Run. I am experiencing laggy UI in our WPF .NET 4.5application (with Caliburn Micro framework).
Basically I am doing (very simplified code snippets):
public class PageViewModel : IHandle
{
...
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
// Makes UI very laggy, but still not dead
await this.contentLoader.LoadContentAsync();
HideLoadingAnimation();
}
}
public class ContentLoader
{
public async Task LoadContentAsync()
{
await DoCpuBoundWorkAsync();
await DoIoBoundWorkAsync();
await DoCpuBoundWorkAsync();
// I am not really sure what all I can consider as CPU bound as slowing down the UI
await DoSomeOtherWorkAsync();
}
}From the articles/videos I read/saw, I know that
await async is not necessarily running on a background thread and to start work in the background you need to wrap it with await Task.Run(async () => ... ). Using async await does not block the UI, but still it is running on the UI thread, so it is making it laggy.Where is the best place to put Task.Run?
Should I just
-
Wrap the outer call because this is less threading work for .NET
-
, or should I wrap only CPU-bound methods internally running with
Task.Run as this makes it reusable for other places? I am not sure here if starting work on background threads deep in core is a good idea.Ad (1), the first solution would be like this:
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
await Task.Run(async () => await this.contentLoader.LoadContentAsync());
HideLoadingAnimation();
}
// Other methods do not use Task.Run as everything regardless
// if I/O or CPU bound would now run in the background.Ad (2), the second solution would be like this:
```
public async Task DoCpuBoundWorkAsync()
{
await Task.Run(() => {
Solution
Note the guidelines for performing work on a UI thread, collected on my blog:
There are two techniques you should use:
1) Use
E.g.,
For more information, see my MSDN article Best Practices in Asynchronous Programming.
2) Use
You should use
So purely CPU-bound work would look like this:
Which you would call using
Methods that are a mixture of CPU-bound and I/O-bound should have an
Which you would also call using
- Don't block the UI thread for more than 50ms at a time.
- You can schedule ~100 continuations on the UI thread per second; 1000 is too much.
There are two techniques you should use:
1) Use
ConfigureAwait(false) when you can.E.g.,
await MyAsync().ConfigureAwait(false); instead of await MyAsync();.ConfigureAwait(false) tells the await that you do not need to resume on the current context (in this case, "on the current context" means "on the UI thread"). However, for the rest of that async method (after the ConfigureAwait), you cannot do anything that assumes you're in the current context (e.g., update UI elements).For more information, see my MSDN article Best Practices in Asynchronous Programming.
2) Use
Task.Run to call CPU-bound methods.You should use
Task.Run, but not within any code you want to be reusable (i.e., library code). So you use Task.Run to call the method, not as part of the implementation of the method.So purely CPU-bound work would look like this:
// Documentation: This method is CPU-bound.
void DoWork();Which you would call using
Task.Run:await Task.Run(() => DoWork());Methods that are a mixture of CPU-bound and I/O-bound should have an
Async signature with documentation pointing out their CPU-bound nature:// Documentation: This method is CPU-bound.
Task DoWorkAsync();Which you would also call using
Task.Run (since it is partially CPU-bound):await Task.Run(() => DoWorkAsync());Code Snippets
// Documentation: This method is CPU-bound.
void DoWork();await Task.Run(() => DoWork());// Documentation: This method is CPU-bound.
Task DoWorkAsync();await Task.Run(() => DoWorkAsync());Context
Stack Overflow Q#18013523, score: 512
Revisions (0)
No revisions yet.