gpt4 book ai didi

c# - 使用 async/await 和 TaskCompletionSource 的奇怪堆栈跟踪增长

转载 作者:太空狗 更新时间:2023-10-29 17:50:18 24 4
gpt4 key购买 nike

以下 C# 代码:

class Program
{
static readonly List<TaskCompletionSource<bool>> buffer =
new List<TaskCompletionSource<bool>>();
static Timer timer;

public static void Main()
{
var outstanding = Enumerable.Range(1, 10)
.Select(Enqueue)
.ToArray();

timer = new Timer(x => Flush(), null,
TimeSpan.FromSeconds(1),
TimeSpan.FromMilliseconds(-1));
try
{
Task.WaitAll(outstanding);
}
catch {}

Console.ReadKey();
}

static Task Enqueue(int i)
{
var task = new TaskCompletionSource<bool>();
buffer.Add(task);
return task.Task;
}

static void Flush()
{
try
{
throw new ArgumentException("test");
}
catch (Exception e)
{
foreach (var each in buffer)
{
var lenBefore = e.StackTrace.Length;
each.TrySetException(e);
var lenAfter = e.StackTrace.Length;
Console.WriteLine($"Before - After: {lenBefore} - {lenAfter}");
Console.WriteLine(e.StackTrace);

}
}
}
}

产生:

Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149
Before - After: 149 - 149

但是当我将 Enqueue 方法更改为异步时:

static async Task Enqueue(int i)
{
var task = new TaskCompletionSource<bool>();
buffer.Add(task);
return await task.Task;
}

结果是:

Before - After: 149 - 643
Before - After: 643 - 1137
Before - After: 1137 - 1631
Before - After: 1631 - 2125
Before - After: 2125 - 2619
Before - After: 2619 - 3113
Before - After: 3113 - 3607
Before - After: 3607 - 4101
Before - After: 4101 - 4595
Before - After: 4595 - 5089

看起来每个缓冲项目的堆栈跟踪递归增长。对于第一项异常堆栈跟踪将是:

   at Program.Flush() in C:\src\Program.cs:line 41
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotificati...
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Program.<Enqueue>d__3.MoveNext() in C:\src\Program.cs:line 34

虽然第二个看起来像下面等等:

   at Program.Flush() in C:\src\Program.cs:line 41
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotificati...
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Program.<Enqueue>d__3.MoveNext() in C:\src\Program.cs:line 34
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotificati...
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Program.<Enqueue>d__3.MoveNext() in C:\src\Program.cs:line 34

这里发生了什么以及如何解决它?

最佳答案

简答:await 尝试解包结果,而带有 await 的方法不会尝试访问任务结果。

更长的答案:

  1. 调用堆栈的重复部分如下所示:

RecurrringCallStack

  1. ValidateEnd TaskAwaiter 的方法被内联,HandleNonSuccessAndDebuggerNotification调用 ThrowForNonSuccess这似乎也是内联的,因为单个异常用于设置 10 个 TaskCompletionSource 的结果,the reason of growing stack of that exception can be seen here .

简单的解决方案是在每个 TrySetException 调用上使用 new Exception("Some descriptive message", originalException)

关于c# - 使用 async/await 和 TaskCompletionSource 的奇怪堆栈跟踪增长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46467275/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com