在“旧”时间内,很容易跟踪哪个方法挂起:只需转到调试器,点击“暂停”按钮并浏览堆栈跟踪。
现在,如果问题出在async方法中,这种方法不起作用 - 因为要执行的下一段代码被隐藏在延续任务中(技术上它甚至没有挂起)...是否存在如何通过任务轻松调试?
UPD。
示例:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
await DoHolyWar();
MessageBox.Show("Holy war complete!");
}
public static async Task DoHolyWar()
{
await DoHolyWarComplicatedDetails();
Console.WriteLine("Victory!");
}
public static async Task DoHolyWarComplicatedDetails()
{
await BurnHeretics();
}
public static Task BurnHeretics()
{
var tcs = new TaskCompletionSource<object>();
// we should have done this, but we forgot
// tcs.SetResult(null);
return tcs.Task;
}
}
请注意,如果你启动它并点击“暂停”,你只会看到DoHolyWar方法挂起,但你不会看到确切的位置。如果你用'.Wait()替换'await',并且做同样的事情,你将能够检查悬挂堆栈跟踪。使用此示例非常简单,但在实际应用程序中,通常很难找到问题。特别是桌面应用程序将在主线程上运行事件循环,因此即使某些内容“挂起”,并且您点击“暂停”,您也不会知道出现了什么问题。
答案 0 :(得分:1)
在这种情况下,你可以做的是进入调试下拉菜单,转到Windows,然后选择“任务”窗口(默认快捷键组合为“ Ctrl + D , K “)。
这可以为您提供有关任务悬挂的线索。
查找具有异常长Duration
值的任务,这表示任务发生了某些事情并且未完成。如果您双击该行,它将带您到等待挂起。
我不确定为什么await BurnHeretics();
没有显示在我的列表中,但我知道这个窗口的行为会有所不同,具体取决于您的操作系统版本,因为它依赖于操作系统功能来跟踪某些任务类型。但至少这会显示await DoHolyWarComplicatedDetails();
正在挂起,这将导致您检查DoHolyWarComplicatedDetails()
,这将导致您检查BurnHeretics();
,这将导致您导致导致挂起的错误。
更新:我刚刚意识到它确实显示await BurnHeretics();
作为块的主要内容。如果您查看Task
列,<DoHolyWarComplicatedDetails>d__3
表示方法DoHolyWarComplicatedDetails
,则会安排编译器生成的类<DoHolyWarComplicatedDetails>d__3
并等待信号到达。“ <DoHolyWarComplicatedDetails>d__3
是await BurnHeretics();
的状态机,如果您使用像DotPeek这样的反编译器并允许显示编译器生成的代码,则可以看到它。
[CompilerGenerated]
private sealed class <DoHolyWarComplicatedDetails>d__3 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder <>t__builder;
private TaskAwaiter <>u__1;
public <DoHolyWarComplicatedDetails>d__3()
{
base..ctor();
}
void IAsyncStateMachine.MoveNext()
{
int num1 = this.<>1__state;
try
{
TaskAwaiter awaiter;
int num2;
if (num1 != 0)
{
awaiter = MainWindow.BurnHeretics().GetAwaiter();
if (!awaiter.IsCompleted)
{
this.<>1__state = num2 = 0;
this.<>u__1 = awaiter;
MainWindow.<DoHolyWarComplicatedDetails>d__3 stateMachine = this;
this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, MainWindow.<DoHolyWarComplicatedDetails>d__3>(ref awaiter, ref stateMachine);
return;
}
}
else
{
awaiter = this.<>u__1;
this.<>u__1 = new TaskAwaiter();
this.<>1__state = num2 = -1;
}
awaiter.GetResult();
awaiter = new TaskAwaiter();
Console.WriteLine("Heretics burned");
}
catch (Exception ex)
{
this.<>1__state = -2;
this.<>t__builder.SetException(ex);
return;
}
this.<>1__state = -2;
this.<>t__builder.SetResult();
}
[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
}
}