Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正确使用Task.Run和异步等待时_C#_Asynchronous_Task_Async Await - Fatal编程技术网

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太多了
您应该使用两种技巧:

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限制):

请注意,我的博客上收集了:

  • 一次阻止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中是更好的方法