我想问您关于何时使用正确的体系结构的意见Task.Run。我在我们的WPF .NET 4.5应用程序(使用Caliburn Micro框架)中遇到了滞后的UI。
Task.Run
基本上我在做(非常简化的代码片段):
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(); } }
从我阅读/看到的文章/视频中,我知道await async并不一定要在后台线程上运行,要在后台开始工作,您需要将其包裹在await中Task.Run(async () => ... )。使用async await不会阻止UI,但仍在UI线程上运行,因此使它变得迟钝。
await
async
Task.Run(async () => ... )
放置Task.Run的最佳位置在哪里?
我应该
打包外部调用,因为这减少了.NET的线程工作
,还是只包装内部运行的受CPU约束的方法,Task.Run因为这使其可以在其他地方重用?我不确定在内核中深入后台线程是否是一个好主意。
广告(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.
广告(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 }
请注意在我的博客上收集的有关在UI线程上执行工作的准则:
您应该使用两种技术:
1)ConfigureAwait(false)可以的话使用。
ConfigureAwait(false)
例如,await MyAsync().ConfigureAwait(false);而不是await MyAsync();。
await MyAsync().ConfigureAwait(false);
await MyAsync();
ConfigureAwait(false)告诉await您不需要在当前上下文上恢复(在这种情况下,“在当前上下文上”表示“在UI线程上”)。但是,对于该async方法的其余部分(ConfigureAwait),您不能做任何假设您处于当前上下文中的操作(例如,更新UI元素)。
ConfigureAwait
有关更多信息,请参见我的MSDN文章异步编程最佳实践。
2)Task.Run用于调用CPU绑定方法。
您应该使用Task.Run,但不要在您希望可重用的任何代码(即库代码)中使用。所以你使用Task.Run来 调用 该方法,而不是作为的一部分 执行 的方法。
因此,纯粹受CPU约束的工作如下所示:
// Documentation: This method is CPU-bound. void DoWork();
您会使用Task.Run以下命令致电:
await Task.Run(() => DoWork());
方法是一个 混合 的CPU绑定和I / O密集型应该有一个Async与文件指出他们的CPU绑定性质签名:
Async
// Documentation: This method is CPU-bound. Task DoWorkAsync();
您也将使用Task.Run它(由于它部分受CPU限制)调用:
await Task.Run(() => DoWorkAsync());