我只是尝试使用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<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;
}
答案 0 :(得分:4)
虽然我熟悉构建WinRT应用程序的正确
async
方法,但我的演示应用程序使用同步Load
来保持简单。
不是真的。与异步代码同步混合非常复杂。在任何地方使用async
都简单得多。
当async
方法在等待任务后继续执行时,它将默认返回其原始上下文。 (我在async
/await
blog post)中更详细地介绍了这一点。某些上下文(例如UI上下文)仅允许单个线程;如果该线程被阻止(例如,在Task.Result
上),则async
方法无法进入该上下文以完成其执行。这会导致死锁。
了解更多信息:
async
/await
FAQ在上下文捕获和恢复方面有很多细节。这种僵局很有名,实际上已经被微软演示了:
答案 1 :(得分:0)
尝试使用ConfigureAwait(false
)和await操作,可能ReadTextAsync
不是线程安全的,所以当await结束并返回UI线程时它会挂起UI线程。