如果我有以下内容:
// a:
// returns a task, then starts and joins it with "await" keyword
var resultA = await GetBigTask();
// b:
// gets a Task<T>, launches it with Start(), then joins it with "await"
var myBigTask = GetBigTask();
myBigTask.Start();
var resultB = await myBigTask;
为了清楚起见,我的评论是否正确?
在尚未启动的任务上使用“await”关键字(如从GetBigTask()
返回的匿名任务)将启动它然后加入它。在已经是.Start()的任务上使用“await”关键字将不会启动它的第二个实例,而是将它加入现有的实例?
因此,如果我有许多完全独立的大任务,那么像“c”而不是“d”那样启动它们总是有益的吗?
// c:
var taskA = GetTaskA();
var taskB = GetTaskB();
var taskC = GetTaskC();
// they are all launched in parallel
taskA.Start(); taskB.Start(); taskC.Start();
// then joined together at the end
await taskA; await taskB; await taskC;
// d:
await GetTaskA();
await GetTaskB(); // not launched until GetTaskA() concludes!
await GetTaskC(); // not launched until GetTaskA() AND B concludes!
这一切都正确吗?如果没有,我如何实现“c”,即一次启动多个(独立)任务,等待所有任务?
答案 0 :(得分:4)
如果没有明确说明您问题的好Minimal, Complete, and Verifiable code example,就无法确定您所展示的代码会发生什么。也就是说,你的问题中至少有一些误解:
- 误解#1:
await
开始一项任务。- 误解#2:
await
加入一个主题。
如果使用await
等待尚未启动的任务,则它本身不会启动任务。它将永远等待,除非在其他地方你有一些代码可以启动任务。
就“连接”而言,该字通常用于描述当前线程等待某个其他线程或任务的操作。这与await
所做的正好相反(是的,我意识到命名法有点令人困惑)。当您的执行到达await
语句时,当前正在执行的方法在该点返回,允许该线程继续执行。如果正在等待的等待完成,则在await
语句后立即执行 resume 。
但在此之前,该线程中的执行不会被阻止(或“加入”)。
await
语句还有一些其他有用的行为:当等待的操作完成时,如果它成功完成,结果值将被await
表达式检索并返回。如果操作不成功而是抛出异常,则异常将被await
表达式解压缩并重新抛出。
在您的示例中,如果GetBigTask()
字面上返回尚未启动的任务对象,那么仅使用await GetBigTask()
将无法执行任何有用的操作,因为等待将永远不会完成。如果任务对象已经已经启动,那么调用myBigTask.Start()
将引发异常。
通常,返回任务对象的异步方法将以已经运行的状态返回这些对象。所以你的问题可能反映了第三种误解:
- 误解#3:
GetBigTask()
,GetTaskA()
等方法会返回尚未启动的任务对象。
当然,如果没有完整的代码示例,则无法确定。但假设这些方法是由熟悉C#中常用异步习惯用法的人编写的,则无需在返回的对象上调用Start()
。
如果确实如此,那么只需执行以下操作即可:
var taskA = GetTaskA();
var taskB = GetTaskB();
var taskC = GetTaskC();
await taskA;
await taskB;
await taskC;
GetTask...()
方法将以已运行状态返回所有任务。按顺序调用await
将按顺序处理每个任务的完成,在完成所有三个任务之前不会继续执行其余任务。