下面是一个在使用该方法时可能出现堆栈溢出的程序示例DependsOnPreviousTaskAsync,这是令人惊讶的,因为我不相信有任何显式的同步递归.
在编码到方法中的断点处发生溢出之前,您可以看到堆栈的示例DoSomething.将有一大堆潜在的异步状态机调用.
由于任务与其前任之间存在依赖关系,因此存在逻辑链,但我很惊讶这串异步调用在调用堆栈上递归显示!
为了解决这个问题,我将方法编码为DependsOnPreviousTaskAsync2,使用旧式ContinueWith连续处理而不是async/await.在这种情况下,在断点处观察到的调用堆栈永远不会很深.
我的问题是,是否有一些关于使用async/await的问题,这会阻止堆栈溢出?或者我是否只是遇到了需要使用变通方法打破async/await状态机固有的惊人递归的边缘情况?
编辑:我已添加TaskContinuationOptions.ExecuteSynchronously到变通方法版本,虽然观察到的调用堆栈可能更深,但我没有看到使用此方法的任何StackOverflowExceptions.无论堆栈溢出检测逻辑被成功地被施加到ContinueWith并且ExecuteSynchronous被未在异步/ AWAIT版本被施加.
class Program
{
public async static Task<int> DependsOnPreviousTaskAsync(Task<int> previousTask)
{
if (previousTask == null)
return 0;
var result = await DoSomethingAsync(previousTask).ConfigureAwait(false);
Console.WriteLine(result);
return result;
}
public static Task<int> DependsOnPreviousTaskAsync2(Task<int> previousTask)
{
// this is a non async/await version of DependsOnPreviousTaskAsync
if (previousTask == null)
return Task.FromResult(0);
var tcs = new TaskCompletionSource<int>();
DoSomethingAsync(previousTask)
.ContinueWith(t =>
{
if …Run Code Online (Sandbox Code Playgroud)