这两种方法有什么区别吗?或者说这两种情况下程序是否运行方式相似?如果有差异,您能说出这些差异是什么吗?
第一种方法:
第二种方法:
第一种方法:
Task myTask = MyFunctionAsync();
await myTask;
第二种方法:
await MyFunctionAsync();
Task myTask = MyFunctionAsync();
await myTask;
await MyFunctionAsync();
await MyFunctionAsync();
Task myTask = MyFunctionAsync();
await myTask;
之所以如此,是因为MyFunctionAsync()
返回的不是任务。使用ValueTask<int>
就足够了,但如果你想要,可以创建其他异步等待对象。但是:如果我们用var
替换Task
,也就是说,
var myTask = MyFunctionAsync();
await myTask;
现在和以前唯一的区别就是,如果我们需要的话,我们可以在代码中的其他点引用myTask
。这并不是特别罕见的情况; 两种主要情况是:
WhenAny
或WhenAll
ValueTask[<T>]
)检查等待期间是否同步完成,以避免在同步情况下状态机开销它们实际上是相同的。不同之处在于第一种方式让您在等待响应之前可以执行更多步骤。因此,您可以在第一种方法中同时启动许多任务,然后使用 await Task.WhenAll(myListOfTasks)
一起等待它们。
例如:
var myTasks = myEmployees.Select(e => ProcessPayrollAsync(e));
await Task.WhenAll(myTasks);
如果需要并发,我建议使用第一种方法;如果是简单情况,使用第二种方法更为简短。
public async Task<int> CalculateResult(InputData data) {
// This queues up the work on the threadpool.
var expensiveResultTask = Task.Run(() => DoExpensiveCalculation(data));
// Note that at this point, you can do some other work concurrently,
// as CalculateResult() is still executing!
// Execution of CalculateResult is yielded here!
var result = await expensiveResultTask;
return result;
}
如上面代码中的注释所指出,在任务运行和 await
调用之间,您可以执行任何其他并发代码。
欲了解更多信息,请阅读此文章。
Task<string> taskReadFile = ReadMyFileAsync(...);
// not awaiting, we can do other things:
DoSomethingElse();
// now we need the result of the file:
string fetchedData = await taskReadFile;
那么会发生什么呢?ReadMyFileAsync是异步的,因此你知道在它的深处,该方法会等待。实际上,如果你忘记await,编译器会警告你。
一旦线程看到了await,它就知道需要等待await的结果,所以它不能继续执行。相反,它会向上调用堆栈继续处理(在我的示例中是DoSomethingElse()),直到它看到一个await。然后再次向上调用堆栈并继续处理,以此类推。
因此,实际上你的第一个和第二个方法之间没有真正的区别。可以将其与以下内容进行比较:
double x = Math.Sin(4.0)
对比
double a = 4.0;
double x = Math.Sin(a);
官方上唯一的区别在于在这些语句之后你仍然可以使用 a。同样,在 await 后,你可以使用来自任务的信息:
Task<MyData> myTask = FetchMyDataAsync(...);
MyData result = await myTask;
// if desired you can investigate myTask
if (result == null)
{
// why is it null, did someone cancel my task?
if (Task.IsCanceled)
{
Yell("Hey, who did cancel my task!");
}
}
但大多数时候,您可能对该任务不感兴趣。如果在任务执行期间没有其他事情可做,我会等待它完成:
MyData fetchedData = await FetchMyDataAsync(...)