0

在分析使用async/awaitdotTrace 功能的应用程序时,我注意到await父方法和子方法在时间上存在一些不一致。让我们考虑这个例子:

static async Task Main()
{
    await ChildMethod();
}

static async Task ChildMethod()
{
    await SomeOperationAsync();
}

有趣的是,方法的await时间Main可能(甚至我觉得奇怪的时间要少,因为直觉上await父母的时间应该至少和孩子的时间一样。ChildMethodawaitawait

对于实数,让我们回到前面的例子并假设SomeOperationAsyncTask.Delay(n)。因此,await父级的时间将是(x针对面向 .NET 6.0的应用程序和针对 .NET Core 3.1 的应用程序),子级的时间将是。x~n<nawait~2*x

这是来自 dotTrace 的屏幕截图,用于了解它的外观(针对面向 .NET Core 3.1 的应用程序和针对 .NET Core 3.1 的应用程序Task.Delay(800)):

在此处输入图像描述

  1. 这是await方法的时候Main567msawait ChildMethod()我希望是这样~800,因为 ChildMethod等待Task.Delay(800)
  2. 这是await方法的时候ChildMethod。为1140 毫秒await Task.Delay(800)。我也希望是这样~800

可能我误解了awaitdotTrace 中的时间,所以如果是,请纠正我。我将其理解为安排任务所需的时间 + 实际任务执行

如果有人知道这种行为是否是预期的并且可以解释如何分析它,那就太好了。

我在 dotTrace 2021.3.3 中使用时间线查看器。

更新

我想我理解我困惑的第一部分,即为什么 等待 时间小于方法中传递的Task.Delay时间Main。这是因为任务的计时器比继续附加(内部调用AwaitUnsafeOnCompleted)更早开始,因此它只等待剩余时间。就我而言,此调用大约需要300 毫秒,因此await时间变为time passed to Task.Delay - time spent on attaching continuation.

4

1 回答 1

0

我认为您误解了 async/await 在 dotnet 中的工作方式。你可以在微软官方文档中查看:https ://docs.microsoft.com/es-es/dotnet/csharp/language-reference/operators/await

基本上,当您执行异步代码(返回任务的方法)时,该方法的执行将发生在独立于原始线程的另一个线程中,并且当您需要该任务的结果时,原始线程将等待第二个完成线程来检索结果。您可以在他们的文档中阅读:

await 运算符不会阻塞评估异步方法的线程。当 await 操作符挂起封闭的 async 方法时,控制权返回给方法的调用者。

看这个例子

public async Task<Person> Main()
{
    string name = await GetName(personId);
    int age = await GetAge(personId);
    return new Person(name, age)
}

public async Task<string> GetName(int personId)
{
    //imagine you have a HttpClient in this class that calls an API to get people info
    return _httpClient.GetAsync($"https://someurl.com/getName/{personId}");
}

public async Task<int> GetAge(int personId)
{
    return _httpClient.GetAsync($"https://someurl.com/getAge/{personId}");
}

这样,主执行线程将创建另外两个线程来获取年龄信息和该 personId 的名称,并且直到该线程需要检索其他两个线程的一些信息时才会停止(返回的行a new Person) 所以在您的代码中发生的情况是,由于没有使用该异步操作的结果,它只是继续原始线程而不停止,因此具有延迟的异步任务持续时间比原始线程长是正常的。

于 2022-02-10T18:35:38.753 回答