C# 这两种任务方法的行为有什么不同?

C# 这两种任务方法的行为有什么不同?,c#,.net,asynchronous,C#,.net,Asynchronous,方法1: private static async Task FirstDelayAsync() { await Task.Delay(1000); } 方法2: private static Task SecondDelayAsync() { return Task.Delay(1000); } 请帮我找出区别: await FirstDelayAsync(); await SecondDelayAsync(); 谢谢。这两个很相似。当遇到async方法时,C#编译器将生

方法1:

private static async Task FirstDelayAsync()
{
    await Task.Delay(1000);
}
方法2:

private static Task SecondDelayAsync()
{
    return Task.Delay(1000);
}
请帮我找出区别:

await FirstDelayAsync();
await SecondDelayAsync();

谢谢。

这两个很相似。当遇到
async
方法时,C#编译器将生成一个状态机,这样返回的
任务
表示方法的完成。由于您的方法所做的唯一事情是等待另一个异步操作,因此这在功能上几乎等同于直接从内部异步操作返回
任务

然而,关于如何抛出来自同步部分的异常,有一个微妙的区别。在
async
方法中执行的任何逻辑,包括方法开头的同步部分(在第一个
wait
语句之前),都将作为异步操作的一部分进行编译。这意味着前提条件异常将不再同步传递,而是通过返回的
任务
异步传递:

private static async Task FirstDelayAsync()
{
    if (StateNotValid)
        throw new NotSupportedException();

    await Task.Delay(1000);
}

private static Task SecondDelayAsync()
{
    if (StateNotValid)
        throw new NotSupportedException();

    return Task.Delay(1000);
}
测试上述代码:

var t1 = FirstDelayAsync();
await t1;                       // exception thrown here

var t2 = SecondDelayAsync();    // exception thrown here
await t2;
如果您在调用异步操作的同一行上等待它,那么这不会有什么区别。然而,如果你推迟等待,这将带来不同;例如,如果您同时启动几个异步操作,然后使用
任务一起等待它们。whalll

var tasks = Enumerable
    .Range(0, 10)
    .Select(i => ProcessAsync(i))
    .ToArray();

await Task.WhenAll(tasks);
在上面的代码段中,从
ProcessAsync
调用引发的同步异常甚至会阻止后续异步操作的启动,因为异常会立即停止枚举。这通常是最好的失败的先决条件,应该停止整个过程


更新:另一个重要的不同之处是,在不使用
ConfigureAwait(false)
的情况下使用
await
将使代码更容易死锁。请参阅。

这两者非常相似。当遇到
async
方法时,C#编译器将生成一个状态机,这样返回的
任务
表示方法的完成。由于您的方法所做的唯一事情是等待另一个异步操作,因此这在功能上几乎等同于直接从内部异步操作返回
任务

然而,关于如何抛出来自同步部分的异常,有一个微妙的区别。在
async
方法中执行的任何逻辑,包括方法开头的同步部分(在第一个
wait
语句之前),都将作为异步操作的一部分进行编译。这意味着前提条件异常将不再同步传递,而是通过返回的
任务
异步传递:

private static async Task FirstDelayAsync()
{
    if (StateNotValid)
        throw new NotSupportedException();

    await Task.Delay(1000);
}

private static Task SecondDelayAsync()
{
    if (StateNotValid)
        throw new NotSupportedException();

    return Task.Delay(1000);
}
测试上述代码:

var t1 = FirstDelayAsync();
await t1;                       // exception thrown here

var t2 = SecondDelayAsync();    // exception thrown here
await t2;
如果您在调用异步操作的同一行上等待它,那么这不会有什么区别。然而,如果你推迟等待,这将带来不同;例如,如果您同时启动几个异步操作,然后使用
任务一起等待它们。whalll

var tasks = Enumerable
    .Range(0, 10)
    .Select(i => ProcessAsync(i))
    .ToArray();

await Task.WhenAll(tasks);
在上面的代码段中,从
ProcessAsync
调用引发的同步异常甚至会阻止后续异步操作的启动,因为异常会立即停止枚举。这通常是最好的失败的先决条件,应该停止整个过程


更新:另一个重要的不同之处是,在不使用
ConfigureAwait(false)
的情况下使用
await
将使代码更容易死锁。参见。

从功能上讲,这两种方法没有区别。它们的工作原理相同

async
await
允许您通过编写看起来像同步代码但实际上是异步的代码来创建复杂的异步方法


对于像您这样的简单情况,第二种方法是首选的,因为第一种方法创建一个状态机来处理异步逻辑。对于复杂的异步方法,这种状态机是绝对需要的,但对于这种简单的情况,这种状态机是不需要的。

从功能上讲,这两种方法没有区别。它们的工作原理相同

async
await
允许您通过编写看起来像同步代码但实际上是异步的代码来创建复杂的异步方法


对于像您这样的简单情况,第二种方法是首选的,因为第一种方法创建一个状态机来处理异步逻辑。这种状态机在复杂的异步方法中是绝对需要的,但在这个简单的情况下是不需要的。

一个称为
第一个
,另一个称为
第二个
。一个是异步的,另一个不是。这不是。你到底想知道什么?这是你的问题吗?@CodeCaster:这是一个合理的问题。即使两者之间没有功能上的差异(事实并非如此),OP也有理由这样问。然而,这可能是一个重复的问题。为了DRY的利益,标记为重复。尽管标题不同,链接的问题及其公认的答案主要讨论
任务。延迟
,而不是
任务。运行
@Douglas我不是说它不合法,我是说我不清楚OP想要什么样的答案。一个是
第一个
,另一个是
第二个
。一个是异步的,另一个不是。这不是。你到底想知道什么?这是你的问题吗?@CodeCaster:这是一个合理的问题。即使两者之间没有功能上的差异(事实并非如此),OP也有理由这样问。然而,这可能是一个重复的问题。为了DRY的利益,标记为重复。尽管标题不同,链接问题及其公认答案主要讨论
Tas的情况