繁体   English   中英

如何找到async / await的“挂起”方法?

[英]How to find which method 'hangs' with async/await?

在“旧”时间,很容易跟踪哪个方法挂起:只需转到调试器,点击“暂停”按钮并浏览堆栈跟踪。

然而,现在,如果问题出在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',并且做同样的事情,你将能够检查悬挂堆栈跟踪。 使用此示例非常简单,但在实际应用程序中,通常很难找到问题。 特别是桌面应用程序将在主线程上运行事件循环,因此即使某些内容“挂起”,并且您点击“暂停”,您也不会知道出现了什么问题。

在这种情况下,您可以进入调试下拉菜单,转到Windows,然后选择“任务”窗口(默认快捷键组合为“ Ctrl + DK ”)。

这可以为您提供有关挂起的任务的线索。

在此输入图像描述

查找具有异常长Duration值的任务,这表示任务发生了某些事情且未完成。 如果双击该行,它将带您到等待挂起。

我不知道为什么要await BurnHeretics(); 我没有在列表中显示,但我知道此窗口的行为会有所不同,具体取决于您的操作系统版本,因为它依赖于操作系统功能来跟踪某些类型的任务。 但至少这会告诉你await DoHolyWarComplicatedDetails(); 悬挂将导致您检查DoHolyWarComplicatedDetails() ,它将引导您检查BurnHeretics(); 这将导致你导致挂起的bug。

更新 :我刚刚意识到它确实显示await BurnHeretics(); 作为主要的事情causnig块。 如果查看Task列, <DoHolyWarComplicatedDetails>d__3表示“在方法DoHolyWarComplicatedDetails ,编译器生成的类<DoHolyWarComplicatedDetails>d__3已被调度,正在等待信号到达。” <DoHolyWarComplicatedDetails>d__3await BurnHeretics();的状态机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)
  {
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM