FileIO.ReadTextAsync偶尔会挂起

我只是尝试使用WinRT,我正在创建的一个演示应用程序是一个基本的“记事本”风格的应用程序,可以加载/保存到本地存储。 虽然我熟悉构建WinRT应用程序的正确async方法,但我的演示应用程序使用同步Load来保持简单。

问题在于,当对Load进行调用时,它会在3次中有2次工作,其余时间应用程序挂起,调用var result = await FileIO.ReadTextAsync(storageFile);

 public class ContentStorage : IContentStorage { private const string FileName = "contents.txt"; public string Load() { return LoadAsync().Result; } public void Save(string content) { SaveAsync(content); } private static async Task LoadAsync() { var storageFile = await LocalFolder.GetFileAsync(FileName); var result = await FileIO.ReadTextAsync(storageFile); return result; } private static async void SaveAsync(string content) { var storageFile = await LocalFolder.CreateFileAsync(FileName, CreationCollisionOption.ReplaceExisting); FileIO.WriteTextAsync(storageFile, content); } private static StorageFolder LocalFolder { get { return ApplicationData.Current.LocalFolder; } } } 

我在这做一些非常愚蠢的事吗?

FWIW,我尝试将Load更改为仅在每一步上明确阻止,这样可以将挂起提高到20,但我仍然不明白为什么它会挂起……

 public string Load() { var storageFile = LocalFolder.GetFileAsync(FileName).AsTask().Result; var result = FileIO.ReadTextAsync(storageFile).AsTask().Result; return result; } 

虽然我熟悉构建WinRT应用程序的正确async方法,但我的演示应用程序使用同步Load来保持简单。

并不是的。 与异步代码同步混合非常复杂。 在任何地方使用async都简单得多。

async方法在等待任务后继续执行时,它将默认返回其原始上下文。 (我在async / await博客文章中详细介绍了这一点)。 某些上下文(例如UI上下文)仅允许单个线程; 如果该线程被阻塞(例如,在Task.Result ),则async方法无法进入该上下文以完成其执行。 这会导致死锁。

欲获得更多信息:

  • async / await FAQ在上下文捕获和恢复方面有很多细节。
  • 并行团队博客上的Stephen Toub有另一个博客文章Await,UI和死锁! 天啊! ,详细解释了这种特殊的死锁情况。
  • 我在MSDN论坛post中为这种死锁写了一个详尽的答案。

这种僵局很有名,它实际上是由微软演示的:

  • 作者:Stephen Toub在BUILD会议上(2011年9月16日)。
  • 来自DevConnections的Lucian Wischik(2012年3月26日)。

尝试将ConfigureAwait(false )与await操作一起使用,可能是ReadTextAsync不是线程安全的,因此当await结束并返回UI线程时它将挂起UI线程。