FileIO.ReadTextAsync occasionally hangs

2019-02-25 14:20发布

I'm just experimenting with WinRT and one demo app i'm creating is a basic "notepad" style app which loads/saves to local storage. Whilst I'm familiar with the proper async approach for building WinRT apps, my demo app is using a synchronous Load to keep things simple.

The problem is that when a call is made to Load, it works 2 out of 3 times and the rest of the time the app hangs on the call 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; }
    }
}

Am I doing something extraordinarily stupid here?

FWIW, I experimented with changing Load to just explicitly block on each step and this improves the hanging to 1 in 20, but I still don't understand why it's hanging at all...

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

    return result;
}

2条回答
疯言疯语
2楼-- · 2019-02-25 14:42

Whilst I'm familiar with the proper async approach for building WinRT apps, my demo app is using a synchronous Load to keep things simple.

Not really. Mixing synchronous with asynchronous code is extremely complex. It's far simpler to just use async everywhere.

When an async method continues execution after waiting for a task, it will return to its original context by default. (I cover this in more detail in my async/await blog post). Some contexts (such as UI contexts) only permit a single thread; if that thread is blocked (e.g., on Task.Result), then the async method cannot enter that context to complete its execution. This causes a deadlock.

For more information:

This deadlock is famous enough that it's actually been demo'd by Microsoft:

查看更多
狗以群分
3楼-- · 2019-02-25 15:00

Try to use ConfigureAwait(false) with the await operation, may be ReadTextAsync is not thread safe, so it will hang the UI thread when the await finished and back to the UI thread.

查看更多
登录 后发表回答