9

async关键字确实会导致CI​​L发生变化(即使方法内没有 await),但它主要是为了允许await存在。

但我没想到会发生以下情况:

static void Main(string[] args)
{
    Task t = Go();
    t.Wait();
}

static async Task Go()
{
    Console.WriteLine(1);
    await AAA(3000);
    Console.WriteLine(2);
}


static  Task<object> AAA(int a) // <--- No `async`
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null));
    return tcs.Task;
}

这个打印:

1
(wait)
2

但如果我改变

static  Task<object> AAA(int a) 

static async  Task<object> AAA(int a) 

它打印:

1
2
(no wait)

问题

为什么我看不到延迟?TCS 仅在三秒后解决。同时,任务还没有解决,应该等待。

4

3 回答 3

8

如果没有async关键字,您TaskCompletionSource将从中返回任务AAA,因此您等待它完成(这将在延迟完成后发生)。

但是,当您添加async关键字时,该方法返回的任务是同步完成的状态机任务。该任务在其中(因此)有TaskCompletionSource的任务,但这不是您正在等待的任务。

如果您希望该方法等待TaskCompletionSource的任务,您可以等待的内部任务Task<Task>

await ((Task) await AAA(3000));

或者等待TaskCompletionSource's 而不是返回它:

async Task AAA(int a)
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null));
    await tcs.Task;
}

甚至更好,只是等待它Task.Delay本身:

async Task<object> AAA(int a)
{
    await Task.Delay(a);
    return null;
}
于 2015-09-25T15:38:02.220 回答
6

因为当你Task从一个异步方法返回时,返回类型Task<object>是你在里面Task<Task>的任务(你期望等待的)得到的。那你应该做的:

static async Task<object> AAA(int a)
{
  await Task.Delay(a);
  return null;
}

简而言之,尽量避免在一种方法中混合 async-await 和直接任务操作。

于 2015-09-25T15:37:21.387 回答
2

正如 Serg 所提到的,在 Visual Studio 中查看这个示例:

        static async Task<int> AAA(int a) // <--- No `async`
        {
             TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
             Task.Delay(a).ContinueWith(b =>
             {
                  tcs.SetResult(1);
             });
             return tcs.Task;
        }

你会得到这样的错误:

由于这是一个异步方法,返回表达式的类型必须是 'int' 而不是 'Task',因为您的方法将同步运行。这就是为什么它需要返回int,而不是Task

于 2015-09-25T15:40:58.847 回答