dotTrace 2025.2 Help

分析异步调用

异步代码的一个缺点是很难分析其性能。 这是因为当异步方法执行时,控制权会切换到不同的线程并返回,从而使生成的调用树变得复杂。

dotTrace 显著简化了异步代码的分析:它会标记 调用树 中的所有 async 调用节点,并将相应的 await 时间和延续代码分组到该节点下。 这意味着您可以快速在一个地方找到异步调用的所有“部分”,而无需在不同的调用栈中搜索它们。

为了更好地理解 dotTrace 如何处理异步代码,请考虑以下示例(代码显示在左侧,相应的 调用树 显示在右侧):

异步调用分析

如您所见,异步调用的所有“部分”都显示在 异步 RunAsyncOperation 节点内:

  • RunAsyncOperation 的总时间计算为

    119 毫秒 = Init() 101 毫秒 + ReadAsync() 13 毫秒 + clr.dll 3.7 毫秒 + FileStream.ctor() 0.6 毫秒

  • Init 方法(101 毫秒)在主线程上执行,因此其时间被添加到 RunAsyncOperation 的总时间中。

  • ReadAsync 在主线程上启动(13 毫秒),但后续任务在线程池中运行。 因此, 任务执行 节点(819 毫秒)的时间显示为灰色,并未添加到 RunAsyncOperation 的总时间中。

    异步调用任务执行
  • 在我们的案例中, await 的时间等于 任务执行 的时间(819 毫秒),但在实际情况下,它可能更高,因为它还包括任务在调度中等待的时间。

  • 延续 节点是一个延续代码,在我们的案例中由一个 ProcessFile 方法(301 毫秒)组成。 由于此调用在线程池中执行,其时间也显示为灰色,并未添加到 RunAsyncOperation 的总时间中。

延续代码的回溯

当然,延续代码的 回溯 不仅会将您带回回调函数,还会带回原始的 async 方法。 这可能非常有用,例如,当延续代码抛出异常时,您需要确定其来源。

异步调用回溯

按异步调用的总时间筛选

要按异步调用的总时间应用筛选器,可以双击 调用树 中的调用节点,或右键点击节点(或其 await延续 节点),然后从上下文菜单中选择 分析异步方法

在您按 async 方法的调用时间应用筛选器后,dotTrace 将仅保留该方法执行的时间间隔。 请注意,您可以通过选择 调用树 中出现的相应复选框来包含或排除延续代码间隔(以及 await 时间节点)。

异步等待筛选器

请注意,如果您应用的筛选器使延续代码超出范围(例如,按主线程筛选),则不会显示 延续 复选框。

调用树中的任务

上述功能不仅适用于 async/await ,还适用于基于 Task 类的所有任务。 运行 节点包含具有任务委托的 任务执行 节点:

异步调用任务

异步调用和事件

调用树 处理调用时间以及时间线分析模式中支持的所有其他类型的事件,例如内存分配或异常。 例如,您可以查看特定异步方法分配了多少内存:

异步调用分配
最后修改日期: 2025年 9月 28日