Yev*_*rov 9 .net c# asynchronous task-parallel-library async-await
以下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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
生产:
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
Run Code Online (Sandbox Code Playgroud)
但是当我将Enqueue方法更改为异步时:
static async Task Enqueue(int i)
{
var task = new TaskCompletionSource<bool>();
buffer.Add(task);
return await task.Task;
}
Run Code Online (Sandbox Code Playgroud)
结果是:
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
Run Code Online (Sandbox Code Playgroud)
对于每个缓冲的项,它看起来像递归堆栈跟踪增长.对于第一项异常堆栈跟踪将是:
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
Run Code Online (Sandbox Code Playgroud)
第二个看起来像下面等等:
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
Run Code Online (Sandbox Code Playgroud)
这里发生了什么以及如何解决它?
简答:await尝试打开结果,而方法withod await不尝试访问任务结果.
更长的回答:
TaskAwaiter正在被内联,并且HandleNonSuccessAndDebuggerNotification导致一个呼叫ThrowForNonSuccess这似乎是太内联和作为唯一的例外是用于为10个设置结果TaskCompletionSourceS, 即异常的生长堆叠的原因这里可以看到.简单的解决方案是new Exception("Some descriptive message", originalException) 在每次TrySetException通话时使用.
| 归档时间: |
|
| 查看次数: |
842 次 |
| 最近记录: |