C# 正确使用Task.Run和异步等待时
我想询问您对何时使用C# 正确使用Task.Run和异步等待时,c#,asynchronous,task,async-await,C#,Asynchronous,Task,Async Await,我想询问您对何时使用Task.Run的正确体系结构的看法。我在我们的WPF.NET4.5中遇到了laggy UI 应用程序(使用Caliburn微框架) 基本上我正在做(非常简化的代码片段): Ad(2),第二种解决方案如下: public async void Handle(SomeMessage message) { ShowLoadingAnimation(); await Task.Run(async () => await this.contentLoader.L
Task.Run
的正确体系结构的看法。我在我们的WPF.NET4.5中遇到了laggy UI
应用程序(使用Caliburn微框架)
基本上我正在做(非常简化的代码片段):
Ad(2),第二种解决方案如下:
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.
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
}
// Documentation: This method is CPU-bound.
void DoWork();
请注意,我的博客上收集了:
- 一次阻止UI线程的时间不要超过50毫秒
- 您可以在UI线程上每秒安排约100次连续操作;1000太多了
configurewait(false)
。
例如,await MyAsync().ConfigureAwait(false)代码>而不是等待MyAsync()代码>
ConfigureAwait(false)
告诉await
您不需要在当前上下文上继续(在本例中,“在当前上下文上”表示“在UI线程上”)。但是,对于该async
方法的其余部分(在ConfigureAwait
之后),您不能执行任何假定您处于当前上下文中的操作(例如,更新UI元素)
有关更多信息,请参阅我的MSDN文章
2)使用任务。运行调用CPU绑定的方法。
您应该使用Task.Run
,但不要在任何希望可重用的代码(即库代码)中运行。因此,您可以使用Task.Run
调用该方法,而不是作为该方法实现的一部分
因此,纯CPU限制的工作如下所示:
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.
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
}
// Documentation: This method is CPU-bound.
void DoWork();
您可以使用任务调用它。运行:
await Task.Run(() => DoWork());
混合CPU绑定和I/O绑定的方法应具有Async
签名,并有文档指出其CPU绑定的性质:
// Documentation: This method is CPU-bound.
Task DoWorkAsync();
您也可以使用Task.Run
调用它(因为它部分受CPU限制):
请注意,我的博客上收集了:
- 一次阻止UI线程的时间不要超过50毫秒
- 您可以在UI线程上每秒安排约100次连续操作;1000太多了
您应该使用两种技巧:
1)尽可能使用configurewait(false)
。
例如,await MyAsync().ConfigureAwait(false)代码>而不是等待MyAsync()代码>
ConfigureAwait(false)
告诉await
您不需要在当前上下文上继续(在本例中,“在当前上下文上”表示“在UI线程上”)。但是,对于该async
方法的其余部分(在ConfigureAwait
之后),您不能执行任何假定您处于当前上下文中的操作(例如,更新UI元素)
有关更多信息,请参阅我的MSDN文章
2)使用任务。运行调用CPU绑定的方法。
您应该使用Task.Run
,但不要在任何希望可重用的代码(即库代码)中运行。因此,您可以使用Task.Run
调用该方法,而不是作为该方法实现的一部分
因此,纯CPU限制的工作如下所示:
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.
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
}
// Documentation: This method is CPU-bound.
void DoWork();
您可以使用任务调用它。运行:
await Task.Run(() => DoWork());
混合CPU绑定和I/O绑定的方法应具有Async
签名,并有文档指出其CPU绑定的性质:
// Documentation: This method is CPU-bound.
Task DoWorkAsync();
您也可以使用Task.Run
调用它(因为它部分受CPU限制):
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);
}
}
公共类页面视图模型:IHandle
{
...
公共异步无效句柄(SomeMessage)
{
显示加载动画();
//使UI非常落后,但仍然没有死亡
等待此消息。contentLoader.LoadContentAsync();
hideloadinganization();
}
}
公共类内容加载器
{
公共异步任务LoadContentAsync()
{
var tasks=新列表();
添加(DoCpuBoundWorkAsync());
添加(DoIoBoundWorkAsync());
添加(DoCpuBoundWorkAsync());
添加(DoSomeOtherWorkAsync());
等待任务.WhenAll(任务).配置等待(false);
}
}
显然,如果任何任务需要来自其他早期任务的数据,这将不起作用,但在大多数情况下,这将为您提供更好的总体吞吐量。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);
}
}
公共类页面视图模型:IHandle
{
...
公共异步无效句柄(SomeMessage)
{
显示加载动画();
//使UI非常落后,但仍然没有死亡
等待此消息。contentLoader.LoadContentAsync();
hideloadinganization();
}
}
公共类内容加载器
{
公共异步任务LoadContentAsync()
{
var tasks=新列表();
添加(DoCpuBoundWorkAsync());
添加(DoIoBoundWorkAsync());
添加(DoCpuBoundWorkAsync());
添加(DoSomeOtherWorkAsync());
等待任务.WhenAll(任务).配置等待(false);
}
}
显然,如果任何任务需要来自其他早期任务的数据,这将不起作用,但在大多数情况下,这将为您提供更好的总体吞吐量。感谢您的快速响应!我知道你发布的链接,看到了你博客中引用的视频。事实上,这就是我发布这个问题的原因——在视频中说(和你的回答一样),你不应该使用Task.runin核心代码。但我的问题是,每次使用这种方法时,我都需要包装它,以免减慢响应速度(请注意,我所有的代码都是异步的,没有阻塞,但没有线程。运行它只是延迟)。我也很困惑,仅仅包装CPU绑定的方法(许多Task.Run调用)还是将所有内容完全包装在一个Task.Run中是更好的方法