何时正确使用Task.Run以及何时仅异步等待

本文翻译自:When correctly use Task.Run and when just async-await

I would like to ask you on your opinion about the correct architecture when to use Task.Run . 我想问您关于何时使用Task.Run的正确体系结构的Task.Run I am experiencing laggy UI in our WPF .NET 4.5 application (with Caliburn Micro framework). 我在我们的WPF .NET 4.5应用程序(使用Caliburn Micro框架)中遇到了滞后的UI。

Basically I am doing (very simplified code snippets): 基本上我在做(非常简化的代码片段):

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();
    }
}

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 () => ... ) . 从我阅读/看到的文章/视频中,我知道await async不一定在后台线程上运行,要在后台启动工作,您需要使用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. 使用async await不会阻止UI,但是仍然在UI线程上运行,因此使它比较滞后。

Where is the best place to put Task.Run? 放置Task.Run的最佳位置在哪里?

Should I just 我应该

  1. Wrap the outer call because this is less threading work for .NET 打包外部调用,因为这减少了.NET的线程工作

  2. , or should I wrap only CPU-bound methods internally running with Task.Run as this makes it reusable for other places? ,还是只包装内部使用Task.Run运行的受CPU约束的方法,因为这可以在其他地方重用? 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: 广告(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.

Ad (2), the second solution would be like this: 广告(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
}

#1楼

参考:https://stackoom.com/question/1dA8H/何时正确使用Task-Run以及何时仅异步等待


#2楼

Note the guidelines for performing work on a UI thread , collected on my blog: 请注意在我的博客上收集的有关在UI线程上执行工作准则

  • Don't block the UI thread for more than 50ms at a time. 不要一次将UI线程阻塞50毫秒以上。
  • You can schedule ~100 continuations on the UI thread per second; 您可以每秒在UI线程上安排约100个连续时间; 1000 is too much. 1000太多了。

There are two techniques you should use: 您应该使用两种技术:

1) Use ConfigureAwait(false) when you can. 1)可以时使用ConfigureAwait(false)

Eg, await MyAsync().ConfigureAwait(false); 例如, await MyAsync().ConfigureAwait(false); instead of await MyAsync(); 而不是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"). ConfigureAwait(false)告诉await您不需要在当前上下文上继续(在这种情况下,“在当前上下文上”意味着“在UI线程上”)。 However, for the rest of that async method (after the ConfigureAwait ), you cannot do anything that assumes you're in the current context (eg, update UI elements). 但是,对于该async方法的其余部分(在ConfigureAwait ),您无法做任何假定您处于当前上下文的操作(例如,更新UI元素)。

For more information, see my MSDN article Best Practices in Asynchronous Programming . 有关更多信息,请参见我的MSDN文章异步编程最佳实践

2) Use Task.Run to call CPU-bound methods. 2)使用Task.Run调用受CPU约束的方法。

You should use Task.Run , but not within any code you want to be reusable (ie, library code). 您应该使用Task.Run ,但不要在要重用的任何代码(即库代码)中使用。 So you use Task.Run to call the method, not as part of the implementation of the method. 因此,您可以使用Task.Run调用方法,而不是将其作为方法实现的一部分。

So purely CPU-bound work would look like this: 因此,纯粹受CPU约束的工作如下所示:

// Documentation: This method is CPU-bound.
void DoWork();

Which you would call using Task.Run : 您将使用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: 方法,这些方法的混合物 CPU绑定和I / O密集型应该有一个Async与文档指出他们的CPU绑定性质签名:

// Documentation: This method is CPU-bound.
Task DoWorkAsync();

Which you would also call using Task.Run (since it is partially CPU-bound): 您也可以使用Task.Run调用它(因为它部分受CPU限制):

await Task.Run(() => DoWorkAsync());

#3楼

One issue with your ContentLoader is that internally it operates sequentially. ContentLoader的一个问题是它在内部按顺序运行。 A better pattern is to parallelize the work and then sychronize at the end, so we get 更好的模式是先并行处理工作,然后最后进行同步,这样我们得到

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);
    }
}

Obviously, this doesn't work if any of the tasks require data from other earlier tasks, but should give you better overall throughput for most scenarios. 显然,如果任何任务都需要其他早期任务中的数据,则此方法将不起作用,但在大多数情况下应为您提供更好的总体吞吐量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值