我使用异步方法作为StorageFile的扩展名来返回文件的大小。问题是,这种方法以某种方式死锁我的Windows应用商店应用。问题正在等待来自file.GetBasicPropertiesAsync的结果。我在异步编程方面不是很有经验,但我认为await语句是为了防止这种情况。有没有人看到一些我不明白的东西?
如果我用GetBasicPropertiesAsync等待一段时间,调试中不会发生死锁。
方法:
public static async Task<string> GetSizeMB(this StorageFile file)
{
var properties = await file.GetBasicPropertiesAsync();
double sizeDouble = Convert.ToDouble(properties.Size) /1000000;
return $"{Math.Round(sizeDouble, 2)} MB";
}
提前感谢提示。
答案 0 :(得分:1)
如果您进一步查看调用堆栈,您几乎肯定会从UI线程调用任务Result
或Wait
成员。 Windows Store应用程序不允许这样做,因为它可以冻结UI线程。
我在博客上详细描述了this kind of deadlock,但摘要版本如下:
当await
必须(异步)等待时,默认情况下它将首先捕获&#34;上下文&#34;。这个&#34;上下文&#34;是SynchronizationContext.Current
,除非它是null
,在这种情况下它是TaskScheduler.Current
。稍后,当(异步)等待完成时,async
方法的剩余部分将继续在捕获的上下文上执行。
在这种情况下,上下文是UI SynchronizationContext
。进一步调用堆栈,另一种方法调用GetSizeMB
并返回一个任务,然后(可能)调用该任务的Result
或Wait
。这是死锁的实际原因,因为该代码在GetSizeMB
完成之前阻塞 UI线程。但是GetSizeMB
无法完成,因为它需要在UI线程上继续执行。
正确的解决方法是将Result
/ Wait
替换为await
。