【问题标题】:Call to await GetFileAsync() never returns and app hangs in WinRT app调用 await GetFileAsync() 永远不会返回并且应用程序在 WinRT 应用程序中挂起
【发布时间】:2012-07-14 02:06:41
【问题描述】:

我试图在应用程序启动时加载和读取设置文件,大约 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)."

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

【问题讨论】:

  • 在调用Wait 时,您正在阻塞 UI 线程。这真是个坏主意。哎呀,这甚至可能是导致问题的原因。
  • 我认为 Jon 是完全正确的 - 你有没有机会将 OnLaunched 标记为异步然后等待 Load() 调用?如果不能,那么另一种方法可能是让 Load 在加载完成后执行一个操作,然后在最后运行该操作(或者,当然,您可以在 Load() 返回的任务上使用 ContinueWith就像你在 async/await 之前所做的一样 :)
  • 你说得对,乔恩和詹姆斯。非常感谢您的意见!我最初使用Wait 是因为我没有意识到您可以将async 添加到覆盖的方法中,而且我不知道OnLaunched 正在UI 线程上运行。删除Wait 并将async 添加到OnLaunched 修复了它!我希望我可以将您的 cmets 标记为答案。

标签: c# file-io windows-8 windows-runtime async-await


【解决方案1】:

默认情况下,当您 await 和尚未完成的 Task 时,该方法会在捕获的上下文(在本例中为 UI 上下文)上恢复。

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

  • OnLaunched 调用 Load(在 UI 上下文中)。
  • Load 等待。这会导致Load 方法返回一个未完成的任务并安排其完成以供以后使用。此延续计划针对 UI 上下文。
  • OnLaunched 阻止从 Load 返回的任务。这会阻塞 UI 线程。
  • GetFileAsync 最终完成,并尝试为 Load 运行延续。
  • Load 的延续等待 UI 线程可用,以便它可以在 UI 上下文中执行。
  • 此时,OnLaunched 正在等待 Load 完成(这样做会阻塞 UI 线程),而 Load 正在等待 UI 线程空闲。死锁。

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

  1. 在您的“库”async 方法中,尽可能使用ConfigureAwait(false)。在您的情况下,这会将 await folder.GetFileAsync("filename.xml"); 更改为 await folder.GetFileAsync("filename.xml").ConfigureAwait(false);
  2. 不要屏蔽Tasks;一直是async。换句话说,将Wait 替换为await

更多信息:

2012 年 7 月 13 日更新: 包含此答案 into a blog post

【讨论】:

  • 优秀的答案!非常感谢您对正在发生的事情的详细解释和广泛的参考文章列表。这让一切变得更加清晰。
  • 这太完美了。这让我感到难以置信的悲伤。
  • 我希望 MS 死了。由于提供了如此疯狂的东西,他们肯定是在寻找人。为什么他们只是没有留下老式线程和同步原语?!白痴。
  • @AlekDepler:Asynchronous programming is the opposite of multithreading。虽然您可以使用线程“伪造”一些异步编程,但您不能总是使用线程来解决异步编程需求。
  • 我可以而且我可以。 “假”是微软每年发明的轮子。目前,我在 WPF 中需要的唯一要求是简单线程。累了……
猜你喜欢
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-12
  • 2014-08-14
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
相关资源
最近更新 更多