使用异步等待或任务?

时间:2014-07-24 06:25:32

标签: c# asynchronous task

您构建了一个复杂的计算算法。这需要相当长的时间才能完成,并且您希望确保应用程序保持响应。你做什么的?

  • 甲。使用async / await。
  • B中。同步运行代码。
  • ℃。使用Task.Run。
  • d。使用BackgroundWorker。

答案是C.但是,有人可以解释为什么A)不正确吗?因为问题并不是说复杂的算法是CPU绑定的。如果它是CPU绑定的,那么我们将不得不使用任务(一种我不太了解的推理,但我知道任务确实有助于导致当前线程被挂起直到它们完成)。另外,请解释如何决定何时使用async / await,并使用Tasks。

3 个答案:

答案 0 :(得分:3)

  

你做什么?

     

一个。使用async / await。

     

B中。同步运行代码。

     

℃。使用Task.Run。

     

d。使用BackgroundWorker。

实现了C#5.0中的async/await功能,以便使异步代码变得简单"写同步代码。如果你研究WinAPI,你会发现几乎所有的异步端点都暴露了一个完全异步的api,意思是there is no thread。进一步观察,您会注意到那些相同的端点正在进行I/O bound操作。

假设您的算法是CPU bound,并且以允许跨多个处理器进行有效计算的方式编写(例如,您的算法没有任何需要同步的共享状态),您可以利用.NET 4.0中引入的Task Parallel Library。 TPL提供了对ThreadPool的抽象,而ThreadPool又试图在多处理器环境中均匀地卸载工作。

await关键字可用于任何等待对象,这意味着该对象实现了GetAwaiter方法。当您使用等待时,您可能希望使用await,并且当等待完成其工作时,希望执行恢复。 Task实现了等待模式,用于描述将在未来完成的工作单元。如果要在工作线程上卸载工作单元并且希望将控制权返回到调用方法,直到该工作完成,则可以使用Task.Runawait

跨多个处理器调度CPU绑定工作的另一种方法是使用公开Parallel.ForParallel.ForEach的{​​{3}}类。

在旁注中,BackgroundWorker也可以用来卸载后台线程上的工作,如果那是问题提出问题的人。自.NET 4.0发布以来,推荐使用TPL。

总而言之,使用任务并行库是将工作卸载到后台线程的推荐方法。您可以将它们与Parallel库结合使用,以最大化算法的并行性。执行此操作后,测试您的代码以确保使用多个线程的开销不会超过同步运行算法所需的时间。

修改

正如Stephan在评论中提到的那样,您可以将Parallel.ForEachTask.Run结合起来卸载后台线程中的并行循环:

var task = Task.Run(() => Parallel.ForEach(.. //Loop here));

答案 1 :(得分:2)

我认为“计算”意味着在没有其他信息的情况下CPU绑定算法。如果算法是IO绑定async / await不仅可以接受,而且是正确的答案。

答案 2 :(得分:1)

我相信这个问题假定你有一个同步编程的算法。问题提到这是一个计算'这模糊地暗示它受CPU限制。它也非常模糊地暗示算法是同步编写的。 E.g:

public int CalculateStuff() {
     ....
}

我要考虑的是创建这种方法的异步对应物:

public async Task<int> CalculateStuffAsync() {
      return await Task.Run(() => CalculateStuff());
}

然后在您的用户界面中:

LoadingIndicator.IsEnabled = true;
ResultTextBox.Text = await CalculateStuffAsync();
LoadingIndicator.IsEnabled = false;

因此,正确答案可能是A和C.无论如何,这个问题太模糊,无法得出任何可靠的结论。