Luk*_*s K 288 c# asynchronous task async-await
我想问你关于正确架构何时使用的意见Task.Run
.我在WPF .NET 4.5应用程序(使用Caliburn Micro框架)中遇到了滞后的UI.
基本上我在做(非常简化的代码片段):
public class PageViewModel : IHandle<SomeMessage>
{
...
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();
}
}
Run Code Online (Sandbox Code Playgroud)
从我阅读/看到的文章/视频中,我知道await
async
不一定在后台线程上运行,并且需要在后台开始工作,需要等待它Task.Run(async () => ... )
.使用async
await
不会阻止UI,但它仍然在UI线程上运行,因此它使它变得迟钝.
放置Task.Run的最佳位置在哪里?
我应该
包装外部调用因为这不是.NET的线程工作
,或者我应该只包装内部运行的CPU绑定方法,Task.Run
因为这使得它可以重用于其他地方?我不确定这里是否开始深入核心的后台线程是一个好主意.
Ad(1),第一个解决方案是这样的:
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.
Run Code Online (Sandbox Code Playgroud)
广告(2),第二个解决方案是这样的:
public async Task DoCpuBoundWorkAsync()
{
await Task.Run(() => {
// Do lot of work here
});
}
public async Task DoSomeOtherWorkAsync(
{
// I am not sure how to handle this methods -
// probably need to test one by one, if it is slowing down UI
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*ary 338
您应该使用两种技术:
1)尽可能使用ConfigureAwait(false)
.
例如,await MyAsync().ConfigureAwait(false);
而不是await MyAsync();
.
ConfigureAwait(false)
告诉await
您不需要在当前上下文中恢复(在这种情况下,"在当前上下文中"表示"在UI线程上").但是,对于该async
方法的其余部分(在此之后ConfigureAwait
),您无法执行任何假设您处于当前上下文中的操作(例如,更新UI元素).
有关详细信息,请参阅我的MSDN文章异步编程中的最佳实践.
2)Task.Run
用于调用CPU绑定方法.
您应该使用Task.Run
,但不能在任何您希望可重用的代码中使用(即库代码).所以你Task.Run
用来调用方法,而不是作为方法实现的一部分.
所以纯粹受CPU限制的工作看起来像这样:
// Documentation: This method is CPU-bound.
void DoWork();
Run Code Online (Sandbox Code Playgroud)
你打电话给谁Task.Run
:
await Task.Run(() => DoWork());
Run Code Online (Sandbox Code Playgroud)
CPU绑定和I/O绑定混合的方法应该有一个Async
签名,文档指出它们的CPU绑定性质:
// Documentation: This method is CPU-bound.
Task DoWorkAsync();
Run Code Online (Sandbox Code Playgroud)
您也可以使用Task.Run
它(因为它部分受CPU限制):
await Task.Run(() => DoWorkAsync());
Run Code Online (Sandbox Code Playgroud)
Pau*_*her 12
ContentLoader的一个问题是内部按顺序运行.一个更好的模式是并行化工作,然后在最后进行同步,所以我们得到了
public class PageViewModel : IHandle<SomeMessage>
{
...
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()
{
var tasks = new List<Task>();
tasks.Add(DoCpuBoundWorkAsync());
tasks.Add(DoIoBoundWorkAsync());
tasks.Add(DoCpuBoundWorkAsync());
tasks.Add(DoSomeOtherWorkAsync());
await Task.WhenAll(tasks).ConfigureAwait(false);
}
}
Run Code Online (Sandbox Code Playgroud)
显然,如果任何任务需要来自其他早期任务的数据,这不起作用,但应该为大多数情况提供更好的整体吞吐量.
归档时间: |
|
查看次数: |
247214 次 |
最近记录: |