什么会导致标有 async 的方法同步执行,即使它包含 await 调用?

发布于 2024-12-25 17:13:24 字数 812 浏览 1 评论 0原文

我正在尝试调试我的同事在他离开时编写的一些代码。

这是调用:

var sw = Stopwatch.StartNew();
logger.Trace("Time A: {0}ms", sw.ElapsedMilliseconds); // Roughly 0ms
pt.Task = ProcessMetricsWorker(pt.CancelTokenSource);
sw.Stop();
logger.Trace("Time B: {0}ms", sw.ElapsedMilliseconds); // Over 20000ms!

这是方法签名:

async Task ProcessMetricsWorker(CancellationTokenSource cancelTokenSource)

该方法大约需要 20 秒才能运行,根据我在上面引用的第一行之前和之后放置的日志记录,该任务正在同步执行,就像异步执行一样部分被忽略。什么会导致这种情况发生?

请注意,异步方法内有一个 await 调用。它在 while 循环内,尽管我无法想象这会产生影响。

// internal to the method referenced above
result = await metricProcessor.ProcessItem(domain);

另外,我创建了一个小型测试应用程序,它运行一个非常简单的异步/等待设置,以确保等待实际上在我运行它的服务器上工作,并且它在我的小测试用例中确实工作正常,只是不在主测试用例中我正在尝试调试应用程序。

I'm trying to debug some code my coworker wrote while he is away.

Here's the call:

var sw = Stopwatch.StartNew();
logger.Trace("Time A: {0}ms", sw.ElapsedMilliseconds); // Roughly 0ms
pt.Task = ProcessMetricsWorker(pt.CancelTokenSource);
sw.Stop();
logger.Trace("Time B: {0}ms", sw.ElapsedMilliseconds); // Over 20000ms!

Here's the method signature:

async Task ProcessMetricsWorker(CancellationTokenSource cancelTokenSource)

The method takes around 20 seconds to run and according to logging I place immediately before and after the first line quoted above, the task is executing synchronously, as though the async part is being ignored. What would cause this to happen?

Note that there is an await call inside the async method. It's inside a while loop, though I can't imagine that would make a difference.

// internal to the method referenced above
result = await metricProcessor.ProcessItem(domain);

Also, I created a small test app that runs a very simple async/await setup to make sure that await actually works on the server I'm running it on, and it does work correctly in my small test case, just not in the main app I'm trying to debug.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谁的新欢旧爱 2025-01-01 17:13:24

每个async 方法都是作为常规方法调用启动的。仅当第一次对可等待对象(尚未完成)执行 await 时,它才会变为异步(就屈服于其调用者而言)。

因此,ProcessMetricsWorker 中发生的情况有两种可能性:

  • 它可能在第一个 await 之前包含一些长时间运行的同步代码。
  • 它等待的许多第一个等待任务可能已经完成。如果它们全部已经完成,那么<​​code>ProcessMetricsWorker实际上是同步的。

“快速路径”博客文章包含有关如何将 await 转换为代码的更多详细信息,并展示了它如何仅在作用于未完成的可等待项时才产生结果。

Every async method is started as a regular method call. It only becomes asynchronous (in the sense of yielding to its caller) the first time it does an await on an awaitable (that is not already completed).

So, there's a couple possibilities of what's going on in ProcessMetricsWorker:

  • It may contain some long-running synchronous code before the first await.
  • Many of the first awaitables that it awaits may already be completed. If they are all already completed, then ProcessMetricsWorker is actually synchronous.

The "fast path" blog post contains more details of how an await is converted to code, and shows how it only yields if it acts on a non-completed awaitable.

悲歌长辞 2025-01-01 17:13:24

嗯,我想我在异步 CTP 中发现了一个错误。

我添加了这个方法:

async Task DummyTask()
{
    await TaskEx.Run(() => Thread.Sleep(1000));
}

然后在 ProcessMetricsWorker 方法中添加了这个方法:

await DummyTask();

嘿,很快,该方法现在是异步的!我想知道编译器是否以某种方式忽略了方法中的内部等待调用,并且所有这些都在 MSIL 代码中同步出现......

Well, I think I found a bug in the Async CTP.

I added this method:

async Task DummyTask()
{
    await TaskEx.Run(() => Thread.Sleep(1000));
}

Then added this right inside the ProcessMetricsWorker method:

await DummyTask();

And hey presto, the method is now asynchronous! I'm wondering if the compiler somehow ignored the inner await call in the method and it all came out synchronous in the MSIL code...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文