【问题标题】:3rd party sync method freezing the UI in .NET 4.7.2 WPF第 3 方同步方法在 .NET 4.7.2 WPF 中冻结 UI
【发布时间】:2019-05-27 20:31:21
【问题描述】:

我有一个使用 WPF MVVM 的 .NET 4.7.2 应用程序。我正在使用制造商提供的库连接到机器人。不幸的是,当 IP 参数错误时,他们连接到机器人的方法会停止 30 秒,这实际上会冻结 UI。

我决定使用 async/await 来解决这个问题,基于this 我认为这是一个 I/O-Bound 问题,但由于我用来连接机器人的方法是同步,我不能等待它。在示例中,我看到他们通常首先使用异步库,当第 3 方提供的同步方法冻结我的 UI 时,我找不到如何解决这个问题。

第一个代码 sn-p 不起作用,当我尝试连接时,我的 UI 停止了 30 秒。

public async Task<bool> ConnectToRobot(string ip = "")
        {
            if (FanucController.IsConnected)
                return true;

            var result = await ConnectToFanuc(ip);

            return result;
        }

private Task<bool> ConnectToFanuc(string ip)
        {
            try
            {
                ((IRobot)FanucController).Connect(ip);
                // Other code for connection

                return Task.FromResult(true);
            }
            catch
            {
                return Task.FromResult(false);
            }
        }

最终我通过使用 CPU-Bound 示例(第二个代码 sn-p)解决了这个问题,但是,这并不是一个真正的 CPU-bound 问题,因此我不确定这是否会在未来引起问题。

public async Task<bool> ConnectToRobot(string ip = "")
        {
            if (FanucController.IsConnected)
                return true;

            var result = await Task.Run(() => ConnectToFanuc(ip));

            return result;
        }

private bool ConnectToFanuc(string ip)
        {
            try
            {
                ((IRobot)FanucController).Connect(ip);
                // Other code for connection

                return true;
            }
            catch
            {
                return false;
            }
        }

有没有更好的方法来解决这个问题?我应该使用 async/await 关键字以外的东西吗?

【问题讨论】:

  • Cpu bound 与否,你探测原始ConnectToFanuc 的方式是错误的,除了你之外,这个方法没有任何async返回一个Task,如果Connect 没有async 变体,你将不得不像你正在做的那样卸载它到另一个线程,但这仍然是可疑的

标签: c# wpf asynchronous async-await


【解决方案1】:

我认为您完全误解了 .net async 的作用。

Task&lt;T&gt; 是 Promise monad 的实现。

这可以处于多种状态(非常简单)。

  • 未完成
  • 完成结果
  • 完成但有错误

这就是 async/await 引擎发挥其魔力的方式。方法可以“完成”而没有结果。

Task.FromResult 在第二个状态下创建一个 Promise。这意味着 async/await 引擎在等待结果的同时没有机会关闭并执行其他操作。

.net async await 框架的一个问题是“Turtles/Async all way down”问题。为了使 async await 正常工作,您需要将所有内容都使用新奇特的 async/Task 实现(这很痛苦,因为一般来说,这意味着要重新实现整个库)。

对此的快速解决方法是使用Task.Run。对于不支持 async/await 的 3rd 方库,这是一种可接受的解决方法。

【讨论】:

    【解决方案2】:

    使用Task.Run 围绕同步方法创建异步包装通常被认为是一种不好的做法,除非您想卸载当前线程以防止它在等待同步方法完成时冻结。

    因此,由于ConnectToFanuc 在这种情况下显然不是异步的,因此使用await Task.Run 调用它是一种可行的解决方法。

    请参阅this blog了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-12
      • 2015-03-08
      • 2015-01-16
      • 1970-01-01
      • 1970-01-01
      • 2018-01-05
      • 1970-01-01
      相关资源
      最近更新 更多