【问题标题】:await in sychronous function?在同步函数中等待?
【发布时间】:2015-08-15 21:41:13
【问题描述】:

是的,我没有找到任何关于这个主题的报道,所以我想我会在这里试一试。我正在尝试在现有函数中添加加载动画,该函数返回字符串列表。我的代码如下所示:

IoC.Get<IEventAggregator>()
         .PublishOnUIThread(new ShowWaitingAnimationArgs
         {
             DisplayMessage = "Updating database file...",
             ShowWaitingAnimation = true
         });
     Task.Factory.StartNew(() =>
     {
         ResultList = update.HandledDifferences(testContext, realContext, imo);
         IoC.Get<IEventAggregator>()
             .PublishOnUIThread(new ShowWaitingAnimationArgs {ShowWaitingAnimation = false});
     });
     return ResultList;

IoC[...] 调用基本上只是发送到框架的消息,它启用然后禁用加载动画。实际工作在 update.HandledDifferences 函数中完成,它基本上更新我的数据库文件并返回可能发生的错误列表。 所以现在我想计算 HandledDifferences 并在计算时显示加载动画(所以 UI 线程和这个都不会被阻塞),完成后,我想返回结果 - 几乎是该代码中编写的内容。 但是,由于它是异步的,它甚至不等待我的 ResultList 被计算出来,它只是返回当时存在的值。

我已经尝试调用任务的返回值并等待任务,这两个选项最终都阻塞了 UI 线程(Task.wait 有时甚至会阻塞任务本身,所以它永远不会完成,我也永远不会过去那条线)。

我现在几乎没有想法了。我只是想等待任务完成,但我不能这样做,因为它不是异步方法,不能合二为一(它必须实现一个接口)。任何想法如何做到这一点?诚然,我并没有真正的异步编程经验,但我在任何地方都找不到类似的东西。

【问题讨论】:

  • 如果你真的不能改变你的方法签名,你的选择是有限的,因为你的方法是设计同步的。如果没有关于您的上下文的更多详细信息,很难推荐更好的替代方案。但是,对我来说,听起来你的方法根本不应该做任何 UI 工作。听起来这是调用者的责任。但是您还必须提供有关调用类/方法的更多详细信息,以查看是否可行。
  • 这个函数在业务逻辑层,它被处理登录请求的视图模型调用。此方法主要检查密码是否正确、数据库是否存在、是否为当前版本、必要时更新,然后在数据库模式中显示待处理的差异。这项工作对我来说真的不应该异步完成
  • @DevilSuichiro:任何基于 I/O 的东西都应该是异步的。数据库调用是基于 I/O 的。在我看来它是异步的。为什么它应该异步完成?
  • 当然是数据库相关的东西(这个函数),只是因为接口问题不能异步完成。我说的是视图模型,它必须同步完成,因为每个步骤都依赖于之前的步骤。所以,如果我理解正确,你建议我应该将 HandledDifferences() 调用+IO 外包给另一个异步函数吗?需要明确的是,因为我现在不能真正尝试一下......对 WhatEverTheHellIWouldCallThatFunction().Result 的调用不会阻塞 UI 线程吗?

标签: c# asynchronous async-await


【解决方案1】:

如果您使用异步等待,则通过在 UI 线程上的 Task 上调用 Wait() 或 Result 将使 UI 线程死锁。

您尚未发布代码所属方法或调用代码的签名,但我认为这可行:

async Task DoWorkAsync()
{
    IoC.Get<IEventAggregator>()
         .PublishOnUIThread(new ShowWaitingAnimationArgs
         {
             DisplayMessage = "Updating database file...",
             ShowWaitingAnimation = true
         });

    var resultList = await Task.Run(
        () => update.HandledDifferences(testContext, realContext, imo));

    IoC.Get<IEventAggregator>()
        .PublishOnUIThread(new ShowWaitingAnimationArgs {ShowWaitingAnimation = false});

    return ResultList;
}

【讨论】:

  • 不幸的是,OP 确实指定由于必须实现接口而无法更改他的方法的签名。所以根据他现有的代码,看起来他不能改变他的方法来返回一个Task&lt;T&gt;。这就是他的问题的重点。
【解决方案2】:

您可以使用AsyncBridge,这将允许您执行异步方法而不会阻塞 UI 线程。

IoC.Get<IEventAggregator>()
         .PublishOnUIThread(new ShowWaitingAnimationArgs
         {
             DisplayMessage = "Updating database file...",
             ShowWaitingAnimation = true
         });

    using (var A = AsyncHelper.Wait)
    {
        A.Run(Task.Run( () => update.HandledDifferences(testContext, realContext, imo)), res => ResultList = res);
    }

    IoC.Get<IEventAggregator>()
             .PublishOnUIThread(new ShowWaitingAnimationArgs {ShowWaitingAnimation = false});

     return ResultList;

【讨论】:

    猜你喜欢
    • 2021-10-16
    • 2020-10-20
    • 2020-12-31
    • 2021-10-16
    • 2022-07-06
    • 2018-01-15
    • 1970-01-01
    • 2023-03-13
    • 2019-04-06
    相关资源
    最近更新 更多