分析异步调用
异步代码的一个缺点是很难分析其性能。 这是因为当异步方法执行时,控制权会切换到不同的线程并返回,从而使生成的调用树变得复杂。
dotTrace 显著简化了异步代码的分析:它会标记 调用树 中的所有 async 调用节点,并将相应的 await 时间和延续代码分组到该节点下。 这意味着您可以快速在一个地方找到异步调用的所有“部分”,而无需在不同的调用栈中搜索它们。
为了更好地理解 dotTrace 如何处理异步代码,请考虑以下示例(代码显示在左侧,相应的 调用树 显示在右侧):

如您所见,异步调用的所有“部分”都显示在 异步 RunAsyncOperation 节点内:
RunAsyncOperation的总时间计算为119 毫秒 =
Init()101 毫秒 +ReadAsync()13 毫秒 +clr.dll3.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 类的所有任务。 运行 节点包含具有任务委托的 任务执行 节点:

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