Async/Await 行为通过堆栈
Async/Await behaviour through the stack
我很好奇 async
的流程是如何跨堆栈工作的。在阅读 C# 中的 async
时,您将不断阅读以下内容的某些版本:
If the task we are awaiting has not yet completed then sign up the
rest of this method as the continuation of that task, and then return
to your caller immediately; the task will invoke the continuation when
it completes.
让我感到困惑的是 return 立即给您的来电者 部分。在下面的示例中,假设某些调用 MethodOneAsync()
,执行命中 MethodOneAsync
中的等待。它会立即 return 到调用它的方法吗?如果是这样,MethodTwoAsync
是如何被执行的?或者它是否继续向下堆栈直到它检测到它实际上被阻塞(即。DoDBWorkAsync()
)然后让出线程?
public static async Task MethodOneAsync()
{
DoSomeWork();
await MethodTwoAsync();
}
public static async Task MethodTwoAsync()
{
DoSomeWork();
await MethodThreeAsync();
}
public static async Task MethodThreeAsync()
{
DoSomeWork();
await DoDBWorkAsync();
}
async
方法中await
之前的部分同步执行。所有 async
方法都是如此。
让我们假设 await DoDBWorkAsync()
我们有 await Task.Delay(1000)
.
这意味着 MethodOneAsync
启动 运行ning,执行 DoSomeWork
并调用 MethodTwoAsync
,然后执行 DoSomeWork
,然后调用 MethodThreeAsync
再次执行 DoSomeWork
.
然后它调用 Task.Delay(1000)
,返回一个未完成的 Task
并等待它。
await 在逻辑上等同于添加一个延续并 return 将任务返回给调用者,MethodTwoAsync
做同样的事情 return Task
给来电者等等。
这样当根延迟Task
完成所有的延续可以运行一个接一个
如果我们让你的例子更复杂一点:
public static async Task MethodOneAsync()
{
DoSomeWorkOne();
await MethodTwoAsync();
DoMoreWorkOne();
}
public static async Task MethodTwoAsync()
{
DoSomeWorkTwo();
await MethodThreeAsync();
DoMoreWorkTwo();
}
public static async Task MethodThreeAsync()
{
DoSomeWorkThree();
await Task.Delay(1000);
DoMoreWorkThree();
}
这在逻辑上类似于使用延续来执行此操作:
public static Task MethodOneAsync()
{
DoSomeWorkOne();
DoSomeWorkTwo();
DoSomeWorkThree();
return Task.Delay(1000).
ContinueWith(_ => DoMoreWorkThree()).
ContinueWith(_ => DoMoreWorkTwo()).
ContinueWith(_ => DoMoreWorkOne());
}
它 return 在 为 MethodTwoAsync
方法触发 Task
之后(或继续执行,如果此 Task
是立即完成),因此内部 Task
正在执行到 SynchronizationContext.Current
环境中。
在 Task
完成后,.NET 状态机 return 执行到 MethodTwoAsync
触发后的点,并处理其余代码。
在 MSDN article 上查看更多信息:
首先,让我做一个不同的例子,这样我的代码就更有意义了
public static async Task MethodOneAsync()
{
DoSomeWork1();
await MethodTwoAsync();
DoOtherWork1();
}
public static async Task MethodTwoAsync()
{
DoSomeWork2();
await MethodThreeAsync();
DoOtherWork2();
}
public static async Task MethodThreeAsync()
{
DoSomeWork3();
await DoDBWorkAsync();
DoOtheWork3();
}
所有 async await 所做的就是将上面的代码变成类似于(但即使这是一个巨大的简化)this
public static Task MethodOneAsync()
{
DoSomeWork1();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = MethodTwoAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork1();
}, null);
});
}
public static Task MethodTwoAsync()
{
DoSomeWork2();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = MethodThreeAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork2();
}, null);
});
}
public static Task MethodThreeAsync()
{
DoSomeWork3();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = DoDbWorkAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork3();
}, null);
});
}.
每个 await 只执行更深的下一层,直到它被迫 return 一个任务,一旦发生这种情况,它就会在任务完成时开始对任务进行延续,并在该延续中传递一个代表 "the rest of the function" 到 SynchronizationContext.Post(
以获得计划执行的代码。
它的调度方式取决于你所在的 SynchronizationContext
。在 WPF 和 Winforms 中,默认情况下它将它排到消息泵中,ASP.NET 它在线程池工作线程中将它排到队列中.
我很好奇 async
的流程是如何跨堆栈工作的。在阅读 C# 中的 async
时,您将不断阅读以下内容的某些版本:
If the task we are awaiting has not yet completed then sign up the rest of this method as the continuation of that task, and then return to your caller immediately; the task will invoke the continuation when it completes.
让我感到困惑的是 return 立即给您的来电者 部分。在下面的示例中,假设某些调用 MethodOneAsync()
,执行命中 MethodOneAsync
中的等待。它会立即 return 到调用它的方法吗?如果是这样,MethodTwoAsync
是如何被执行的?或者它是否继续向下堆栈直到它检测到它实际上被阻塞(即。DoDBWorkAsync()
)然后让出线程?
public static async Task MethodOneAsync()
{
DoSomeWork();
await MethodTwoAsync();
}
public static async Task MethodTwoAsync()
{
DoSomeWork();
await MethodThreeAsync();
}
public static async Task MethodThreeAsync()
{
DoSomeWork();
await DoDBWorkAsync();
}
async
方法中await
之前的部分同步执行。所有 async
方法都是如此。
让我们假设 await DoDBWorkAsync()
我们有 await Task.Delay(1000)
.
这意味着 MethodOneAsync
启动 运行ning,执行 DoSomeWork
并调用 MethodTwoAsync
,然后执行 DoSomeWork
,然后调用 MethodThreeAsync
再次执行 DoSomeWork
.
然后它调用 Task.Delay(1000)
,返回一个未完成的 Task
并等待它。
await 在逻辑上等同于添加一个延续并 return 将任务返回给调用者,MethodTwoAsync
做同样的事情 return Task
给来电者等等。
这样当根延迟Task
完成所有的延续可以运行一个接一个
如果我们让你的例子更复杂一点:
public static async Task MethodOneAsync()
{
DoSomeWorkOne();
await MethodTwoAsync();
DoMoreWorkOne();
}
public static async Task MethodTwoAsync()
{
DoSomeWorkTwo();
await MethodThreeAsync();
DoMoreWorkTwo();
}
public static async Task MethodThreeAsync()
{
DoSomeWorkThree();
await Task.Delay(1000);
DoMoreWorkThree();
}
这在逻辑上类似于使用延续来执行此操作:
public static Task MethodOneAsync()
{
DoSomeWorkOne();
DoSomeWorkTwo();
DoSomeWorkThree();
return Task.Delay(1000).
ContinueWith(_ => DoMoreWorkThree()).
ContinueWith(_ => DoMoreWorkTwo()).
ContinueWith(_ => DoMoreWorkOne());
}
它 return 在 为 MethodTwoAsync
方法触发 Task
之后(或继续执行,如果此 Task
是立即完成),因此内部 Task
正在执行到 SynchronizationContext.Current
环境中。
在 Task
完成后,.NET 状态机 return 执行到 MethodTwoAsync
触发后的点,并处理其余代码。
在 MSDN article 上查看更多信息:
首先,让我做一个不同的例子,这样我的代码就更有意义了
public static async Task MethodOneAsync()
{
DoSomeWork1();
await MethodTwoAsync();
DoOtherWork1();
}
public static async Task MethodTwoAsync()
{
DoSomeWork2();
await MethodThreeAsync();
DoOtherWork2();
}
public static async Task MethodThreeAsync()
{
DoSomeWork3();
await DoDBWorkAsync();
DoOtheWork3();
}
所有 async await 所做的就是将上面的代码变成类似于(但即使这是一个巨大的简化)this
public static Task MethodOneAsync()
{
DoSomeWork1();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = MethodTwoAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork1();
}, null);
});
}
public static Task MethodTwoAsync()
{
DoSomeWork2();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = MethodThreeAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork2();
}, null);
});
}
public static Task MethodThreeAsync()
{
DoSomeWork3();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = DoDbWorkAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork3();
}, null);
});
}.
每个 await 只执行更深的下一层,直到它被迫 return 一个任务,一旦发生这种情况,它就会在任务完成时开始对任务进行延续,并在该延续中传递一个代表 "the rest of the function" 到 SynchronizationContext.Post(
以获得计划执行的代码。
它的调度方式取决于你所在的 SynchronizationContext
。在 WPF 和 Winforms 中,默认情况下它将它排到消息泵中,ASP.NET 它在线程池工作线程中将它排到队列中.