我正在尝试在应用程序启动时加载和读取设置文件,大约90%的时间,await GetFileAsync("filename.xml");
永远不会返回,因此,挂起应用程序。
大约四分之一的时间,如果我单步执行代码,它实际上会返回并读取文件。
以下是代码的简化版本:
App.xaml.cs:
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
FileLoader.Load().Wait();
// File-load dependent stuff
}
FileLoader.cs:
public async static Task Load()
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file;
bool fileExists = true;
try
{
// The following line (often) never returns
file = await folder.GetFileAsync("filename.xml");
{
catch
{
fileExists = false;
}
// Do stuff with loaded file
}
如果我在Visual Studio中观看“输出”窗口,经过一段时间的等待后,我得到"The thread '<No Name>' (0x30c) has exited with code 0 (0x0)."
有没有人知道这里发生了什么?
答案 0 :(得分:51)
默认情况下,当您await
Task
尚未完成时,该方法将在捕获的上下文(在本例中为UI上下文)中恢复。
所以,这就是你的代码失败的原因:
OnLaunched
调用Load
(在UI上下文中)。Load
等待着。这会导致Load
方法返回一个不完整的任务,并安排其完成以供日后使用。此延续计划用于UI上下文。OnLaunched
阻止Load
返回的任务。这会阻止UI线程。GetFileAsync
最终完成,并尝试运行Load
的延续。Load
的延续等待UI线程可用,以便它可以在UI上下文中执行。OnLaunched
正在等待Load
完成(通过这样做来阻止UI线程),Load
正在等待UI线程空闲。死锁。这些最佳做法可以避免这种情况:
async
方法中,尽可能使用ConfigureAwait(false)
。在您的情况下,这会将await folder.GetFileAsync("filename.xml");
更改为await folder.GetFileAsync("filename.xml").ConfigureAwait(false);
。Task
s;它一直是async
。换句话说,将Wait
替换为await
。了解更多信息:
async
/await
intro post,其中包括Task
等待者如何使用SynchronizationContext
的简要说明,并介绍了一些最佳做法。更新,2012-07-13:纳入此答案into a blog post。