什么是一个严格的定义应该是一个等待的"等待的"任务?

时间:2016-12-09 06:37:17

标签: c# .net asynchronous async-await task-parallel-library

我试图深入了解async - await。每当我看到其工作原理的示例时,该示例都使用名为await或类似的LongRunningTask方法,其中包含Task.Delaynew WebClient().Download("http://google.com")或类似内容。我试图找出应该等待什么的严格定义。它不能简单地成为一个长期运行的任务,因为长期运行的任务可能就像找到一个大小为1,000,000,000的数组的最大子阵列,这不会给任何一个如果await - async没有创建任何新主题,那么await的性能优势就会受到影响。

根据我的理解,如果您有类似

的内容
var task = LongRunningTask();
DoSomething();
int x = DoSomethingElse();
int y = await task;
int z = x + y;

然后是块

DoSomething();
int x = DoSomethingElse();

是您向编译器暗示的内容

  

"嘿,编译器,如果你可以验证这个块没有   依赖于LongRunningTask,反之亦然,那么你就可以开始了   将你的工作分成LongRunningTask和这段代码。   当你完成此任务时,你还没有完成LongRunningTask   大块的代码,然后只是完成LongRunningTask的工作   为什么我告诉你await它。"

你能帮我理顺吗?

3 个答案:

答案 0 :(得分:5)

await不如你想象的那么神奇。在您的示例中,关于是否使用其他线程或I / O完成例程等的决定不在您显示的代码的任何中。

LongRunningTask的实现,作为一种返回已经开始的Task的方法,已做出关于如何 的任何复杂决策Task已完成。

所有await所做的就是等待(正如其名称所暗示的)已经已经开始完成的事情。

现在,如果通过创建新任务实现 LongRunningTask,那些任务正在使用使用该线程池的默认调度程序,如果您当前使用方法已经在线程池线程上运行 LongRunningTask创建的一些任务正在等待线程池线程变为可用,那么可能当遇到await时,运行代码的同一个线程变得可用,并将用于开始运行其中一个等待任务。但这主要是你不需要考虑的事情。

答案 1 :(得分:1)

出于您的问题的目的,长时间运行的任务是涉及输入/输出(I / O)的任何任务。

这是可以等待的优秀任务类,因为I / O通常会发生的事情是计算机发出启动I / O的指令,然后只是等待(通常处于低CPU状态)用于完成I / O.

因此,new WebClient().Download("http://google.com")是涉及I / O的任务的一个很好的例子,因为为了执行此任务,机器需要准备一个google.com的请求,开始通过套接字发送它,等待请求完全发送,然后等待响应开始到达,然后等待响应完全到达。

但是,这个定义并不严格;即使找到一个大小为1,000,000,000的数组的最大子数组也可能是一个长期运行的任务,如果它是通过生成一个新线程实现的,因为就调用线程而言,我们将有一个非常类似的场景:我们设置 - 启动操作,(生成新线程,将其传递给要搜索的数组),然后等待结果,什么都不做。

修改

鉴于上述情况,最大阵列的巨型阵列示例可以被认为是一个红色的鲱鱼,因为为了异步等待的目的,问题是它是否是或者它不是。 ta长时间运行的任务取决于它是否在单独的线程中启动。

因此,对长期运行任务的更好定义可能是:

  

任何需要花费这么长时间才能完成的任务   阻止在当前正在执行的线程中等待。

因此,例如,如果您正在编写交互式(GUI)应用程序,并且希望保证对人类用户的响应时间为200毫秒,则任何需要花费更长时间的任务都是长时间运行的任务:你启动它,等待它,并且只要它正在运行你的GUI仍然是响应。另一方面,如果你正在编写一个批处理工作,这个工作要在一夜之间运行来处理一些大数据,那么几乎没有任务值得考虑作为一个长期运行的任务。

答案 2 :(得分:0)

如上面的答案中所述,任务CAN启动不同的线程并等待该特定任务的等待结果。

通常像API调用这样的任务完全独立于处理能力,即使你有最大的RAM,CPU对你正在寻求的响应没有影响或影响很小,即IO绑定延迟,这是需要完成的任务。这些任务由工作线程在内部完成,通常应该等待

参考:Essential C#6.0(第5版)