C# 调用wait GetFileAsync()将永远不会返回,并且应用程序将挂起在WinRT应用程序中

C# 调用wait GetFileAsync()将永远不会返回,并且应用程序将挂起在WinRT应用程序中,c#,file-io,windows-8,windows-runtime,async-await,C#,File Io,Windows 8,Windows Runtime,Async Await,我试图在应用程序启动时加载和读取一个设置文件,等待GetFileAsync(“filename.xml”)永不返回,因此挂起应用程序 大约有四分之一的时间,如果我单步执行代码,它实际上会返回并读取文件 下面是代码的一个非常简化的版本: App.xaml.cs: protected override void OnLaunched(LaunchActivatedEventArgs args) { FileLoader.Load().Wait(); // File-load dep

我试图在应用程序启动时加载和读取一个设置文件,
等待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中查看输出窗口,等待一段时间后,我会得到“线程”(0x30c)已退出,代码为0(0x0)。”


有人知道这里发生了什么吗?

默认情况下,当您等待尚未完成的
任务时,该方法将在捕获的上下文(在本例中为UI上下文)上恢复

下面是代码失败的原因:

  • OnLaunched
    调用
    Load
    (在UI上下文中)
  • 加载
    等待。这会导致
    Load
    方法返回一个未完成的任务,并将其完成时间安排在以后。此延续是为UI上下文安排的
  • OnLaunched
    对从
    Load
    返回的任务执行块。这将阻止UI线程
  • GetFileAsync
    最终完成,并尝试运行
    Load
    的延续
  • Load
    的continuation将等待UI线程可用,以便它可以在UI上下文中执行
  • 此时,
    OnLaunched
    正在等待
    Load
    完成(通过这样做阻止UI线程),而
    Load
    正在等待UI线程释放。僵局
这些最佳做法避免了这种情况:

  • 在“库”
    async
    方法中,尽可能使用
    ConfigureAwait(false)
    。在您的情况下,这将改变
    await folder.GetFileAsync(“filename.xml”)
    to
    await folder.GetFileAsync(“filename.xml”).ConfigureAwait(false)
  • 不要阻塞
    任务
    s;它一直是异步的。换句话说,将
    Wait
    替换为
    Wait
  • 有关更多信息:

    • My,其中简要介绍了
      任务
      等待者如何使用
      同步上下文
      ,并介绍了一些最佳实践
    • 第二部分,详细介绍了上下文
    • 这个
    • Stephen Toub和

    更新,2012-07-13:包含了这个答案。

    您正在通过调用
    等待来阻止UI线程。那真是个坏主意。见鬼,这甚至可能是导致问题的原因。我认为Jon完全正确-您是否有可能将OnLaunched标记为async,然后等待Load()调用?如果不能,那么另一种方法可能是让Load在加载完成后执行一个操作,然后在最后运行该操作(或者,当然,您可以在Load()返回的任务上使用ContinueWith,就像在async/Wait:之前一样)。Jon和James,您都是对的。非常感谢您的投入!我最初使用的是
    Wait
    ,因为我没有意识到可以将
    async
    添加到重写的方法中,而且我不知道
    OnLaunched
    正在UI线程上运行。删除
    Wait
    并将
    async
    添加到
    OnLaunched
    修复了它!我希望我能把你的评论作为答案。很好的答案!非常感谢您对正在发生的事情的详细解释和参考文章的广泛列表。这让一切都更清楚了,这太完美了。这让我省去了太多的悲伤,真是难以置信。我希望MS死了。因为提供了这些疯狂的东西,他们肯定是在找人。他们为什么不留下老式的线程和同步原语?!笨蛋。@AlekDepler:。虽然您可以使用线程“伪造”一些异步编程,但您不能总是使用线程来解决异步编程需求。我可以,我也可以。“假”是微软每年发明的轮子。目前,我在WPF中唯一需要的是简单线程。疲倦的