是什么导致一个标记为async的方法同步执行,即使它包含一个等待调用
本文关键字:执行 同步 方法 等待 包含一 调用 async 一个 是什么 记为 | 更新日期: 2023-09-27 18:19:39
我正试着调试同事不在时写的一些代码。
电话是这样的:
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秒,根据我在上面引用的第一行前后放置的日志记录,任务正在同步执行,就好像async
部分被忽略了一样。是什么原因导致了这种情况的发生?
请注意,异步方法内部有一个await
调用。这是一个暂时的循环,尽管我无法想象这会有什么不同。
// internal to the method referenced above
result = await metricProcessor.ProcessItem(domain);
此外,我创建了一个小型测试应用程序,它运行一个非常简单的异步/等待设置,以确保等待在我运行它的服务器上实际工作,并且它在我的小型测试用例中正确工作,只是不在我试图调试的主应用程序中。
每个async
方法都作为常规方法调用启动。它只有在第一次对awaitable(尚未完成)执行await
时才变得异步(从向调用者让步的意义上讲)。
因此,ProcessMetricsWorker
:中发生的事情有两种可能性
- 它可能在第一个
await
之前包含一些长时间运行的同步代码 - 它
await
的许多第一批获奖作品可能已经完成。如果所有都已完成,则ProcessMetricsWorker
实际上是同步的
"快速路径"博客文章包含了await
如何转换为代码的更多细节,并展示了它如何仅在对未完成的awarite进行操作时产生效果。
好吧,我想我在异步CTP中发现了一个错误。
我添加了这个方法:
async Task DummyTask()
{
await TaskEx.Run(() => Thread.Sleep(1000));
}
然后在ProcessMetricsWorker
方法中添加了这个:
await DummyTask();
嘿,presto,这个方法现在是异步的!我想知道编译器是否以某种方式忽略了方法中的内部等待调用,并且在MSIL代码中所有调用都是同步的。。。