FileIO.ReadTextAsync 偶尔会挂起

本文关键字:挂起 偶尔 ReadTextAsync FileIO | 更新日期: 2023-09-27 18:34:51

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

问题是,当调用 Load ,它工作 2 次中的 3 次,其余时间应用程序挂在呼叫上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<string> 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更改为在每个步骤上显式阻止,这将悬挂提高到 1/20,但我仍然不明白为什么它会挂起......

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

FileIO.ReadTextAsync 偶尔会挂起

虽然我熟悉构建 WinRT 应用的正确async方法,但我的演示应用正在使用同步Load来简化操作。

没有。将同步代码与异步代码混合在一起非常复杂。在任何地方使用async要简单得多。

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

欲了解更多信息:

  • async/await常见问题解答有很多关于上下文捕获和恢复的详细信息。
  • 并行团队博客上的 Stephen Toub 有另一篇博客文章 等待、UI 和死锁!哦,我的!,它详细解释了这种特殊的僵局情况。
  • 我在MSDN论坛帖子中为这种僵局写了一个详尽的答案。

这个死锁足够有名,以至于它实际上已经被Microsoft演示过:

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

尝试将 ConfigureAwait(false ( 与 await 操作一起使用,可能会ReadTextAsync线程不安全,因此它会在 await 完成后挂起 UI 线程并返回到 UI 线程。