调用 await GetFileAsync() 永远不会返回,并且应用程序在 WinRT 应用程序中挂起 [英] Call to await GetFileAsync() never returns and app hangs in WinRT app

查看:26
本文介绍了调用 await GetFileAsync() 永远不会返回,并且应用程序在 WinRT 应用程序中挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在应用程序启动时加载和读取设置文件,大约 90% 的时间,await GetFileAsync("filename.xml"); 永远不会返回,因此,挂起应用程序.

I'm attempting to load and read a settings file on application launch, and about 90% of the time, the await GetFileAsync("filename.xml"); never returns, thus, hanging the application.

大约四分之一的时间,如果我单步执行代码,它实际上会返回并读取文件.

About a quarter of the time, if I step through the code, it'll actually return and read the file.

这是一个非常简化的代码:

Here's a very simplified version of the code:

App.xaml.cs:

App.xaml.cs:

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    FileLoader.Load().Wait();

    // File-load dependent stuff
}

FileLoader.cs:

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) 已退出,代码为 0 (0x0)."

If I watch the Output window in Visual Studio, after awhile of waiting I get "The thread '<No Name>' (0x30c) has exited with code 0 (0x0)."

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

Does anyone have any idea of what's happening here?

推荐答案

默认情况下,当你 await 一个尚未完成的 Task 时,方法会在捕获的上下文(在本例中为 UI 上下文).

By default, when you await a Task that has not yet completed, the method resumes on a captured context (in this case, the UI context).

所以,这就是您的代码失败的原因:

So, here's why your code is failing:

  • OnLaunched 调用 Load(在 UI 上下文中).
  • 加载等待.这会导致 Load 方法返回一个未完成的任务并安排其完成以供以后使用.此延续计划针对 UI 上下文.
  • OnLaunched 阻塞从 Load 返回的任务.这会阻塞 UI 线程.
  • GetFileAsync 最终完成,并尝试运行 Load 的延续.
  • Load 的延续等待 UI 线程可用,以便它可以在 UI 上下文中执行.
  • 此时,OnLaunched 正在等待 Load 完成(这样做会阻塞 UI 线程),而 Load 正在等待UI 线程是空闲的.死锁.
  • OnLaunched calls Load (within the UI context).
  • Load awaits. This causes the Load method to return an incomplete task and schedule its completion for later. This continuation is scheduled for the UI context.
  • OnLaunched blocks on the task returned from Load. This blocks the UI thread.
  • GetFileAsync eventually completes, and attempts to run the continuation for Load.
  • The continuation for Load waits for the UI thread to be available so it can execute in the UI context.
  • At this point, OnLaunched is waiting for Load to complete (blocking the UI thread by doing so), and Load is waiting for the UI thread to be free. Deadlock.

这些最佳做法可以避免这种情况:

These best practices avoid this situation:

  1. 在您的库"async 方法中,尽可能使用 ConfigureAwait(false).在您的情况下,这会将 await folder.GetFileAsync("filename.xml"); 更改为 await folder.GetFileAsync("filename.xml").ConfigureAwait(false);.
  2. 不要阻塞 Tasks;它一直是 async .换句话说,将 Wait 替换为 await.
  1. In your "library" async methods, use ConfigureAwait(false) whenever possible. In your case, this would change await folder.GetFileAsync("filename.xml"); to await folder.GetFileAsync("filename.xml").ConfigureAwait(false);.
  2. Don't block on Tasks; it's async all the way down. In other words, replace Wait with await.

更多信息:

  • Await, and UI, and deadlocks! Oh, my!
  • My async/await intro post, which includes a brief description of how Task awaiters use SynchronizationContext and introduces some best practices.
  • The Async/Await FAQ, which goes into more detail on the contexts.
  • This MSDN forum post.
  • Stephen Toub demos this deadlock, and so does Lucian Wischik.

2012 年 7 月 13 日更新: 包含此答案 写入博客文章.

这篇关于调用 await GetFileAsync() 永远不会返回,并且应用程序在 WinRT 应用程序中挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆