返回结果后,控制流如何保留在异步方法范围内?这类似于变量的闭包吗?

How does control flow remain in the async method scope after it has returned the result? Is this similar to closure for variables?

在下面的代码中,42 在 "Almost done" 之前打印到控制台。既然42已经被return编辑了,怎么控件还在AsyncCheck?我知道如果任务在 'await' 时还没有完成,它将 return 控制但是这里我有一个明确的 return 声明,所以我很难理解这个.

async static Task<int> AsyncCheck()
{
   await Task.Factory.StartNew( async () => 
    {
        Console.WriteLine("Start awesome work");
        await Task.Delay(1000);
        Console.WriteLine("Almost done");
        await Task.Delay(1000);
        Console.WriteLine("Ok, done!");
    });

   return 42;
}

async static void AsyncCall()
{
    int result = await AsyncCheck();
    Console.WriteLine(result);
}

我正在使用 'async void' 来检查这个示例。

您不应该将 Task.Factory.StartNewasync-await 一起使用。您应该使用 Task.RunTask.Factory.StartNew 出现在 .Net 4.0 中,但没有考虑 async-await。您仍然可以使用它,但除非您有充分的理由,否则 Task.Run 是一个更安全的选择。

不是返回 Task,而是 returns 一个 Task<Task>,您需要在等待之前解包:

Task<Task> task = Task.Factory.StartNew( async () => 
{
    Console.WriteLine("Start awesome work");
    await Task.Delay(1000);
    Console.WriteLine("Almost done");
    await Task.Delay(1000);
    Console.WriteLine("Ok, done!");
});
Task unwrappedTask = task.Unwrap();
await unwrappedTask

没有它,您就不会真正等待 lambda 完成。您所做的只是使用 ThreadPool 线程来启动此异步方法。

基本上,您是在代码流继续进行的同时在不同的线程上并行执行 lambda。这就是为什么您在 "Almost done"

之前看到“42”

让我们脱糖吧!你有

async static Task<int> AsyncCheck()
{
   await Task.Factory.StartNew( async () => 
    {
        Console.WriteLine("Start awesome work");
        await Task.Delay(1000);
        Console.WriteLine("Almost done");
        await Task.Delay(1000);
        Console.WriteLine("Ok, done!");
    });

   return 42;
}

async static void AsyncCall()
{
    int result = await AsyncCheck();
    Console.WriteLine(result);
}

编译器将其转换为以下内容:

static Task<int> AsyncCheck()
{
   Task t = Task.Factory.StartNew( () => 
    {
        Console.WriteLine("Start awesome work");
        Task d1 = Task.Delay(1000);
        d1.ContinueWith(t1 => {
          Console.WriteLine("Almost done");
          Task t2 = Task.Delay(1000);
          t2.ContinueWith( tt2 => {
            Console.WriteLine("Ok, done!");
          }
        }
    });
   //no dependecies on t, so just return straight away
   return Task.FromResult(42);
}

static void AsyncCall()
{
    Task<int> result = AsyncCheck();
    result.ContinueWith( t => {
      Console.WriteLine(t.Result);
    })
}
一旦任务完成,

ContinueWith 将 运行 它的正文。这应该使控制流程清晰。