2

我只是在试验 WinRT,我正在创建的一个演示应用程序是一个基本的“记事本”风格的应用程序,它可以加载/保存到本地存储。虽然我熟悉async构建 WinRT 应用程序的正确方法,但我的演示应用程序使用同步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<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为仅在每个步骤上显式阻止,这将悬挂提高到 20 分之一,但我仍然不明白为什么它完全悬挂......

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

    return result;
}
4

2 回答 2

4

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

并不真地。将同步代码与异步代码混合起来非常复杂。async随处使用要简单得多。

当一个async方法在等待一个任务后继续执行时,默认会回到原来的上下文。(我在我的async/await博客文章中对此进行了更详细的介绍)。一些上下文(比如 UI 上下文)只允许一个线程;如果该线程被阻塞(例如 on Task.Result),则该async方法无法进入该上下文以完成其执行。这会导致死锁。

了解更多信息:

这种死锁非常有名,以至于微软实际上已经对其进行了演示:

于 2012-05-23T13:14:11.487 回答
1

尝试将ConfigureAwait(false) 与 await 操作一起使用,可能ReadTextAsync不是线程安全的,所以它会在 await 完成时挂起 UI 线程并返回到 UI 线程。

于 2012-10-15T07:09:58.530 回答