第三方同步方法冻结了.NET 4.7.2 WPF

时间:2019-05-27 02:16:17

标签: c# wpf asynchronous async-await

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

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

第一个代码段不起作用,当我尝试连接时,我的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绑定示例(第二个代码段)解决了这个问题,但是,这实际上并不是CPU受限的问题,因此我不确定将来是否会引起问题。

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关键字外,我还应该使用其他内容吗?

2 个答案:

答案 0 :(得分:1)

我认为您完全误解了.net异步在做什么。

Task<T>是Promise monad的实现。

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

  • 不完整
  • 完成结果
  • 完成错误

这是异步/等待引擎执行其魔术的方式。方法可以“完成”而没有结果。

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

.net异步等待框架的一个问题是“ Turtles / Async down down”问题。为了使异步等待正常工作,您需要使用新的,有序的异步/任务实现来完成所有工作(这很痛苦,因为通常来说,这意味着要重新实现整个库)。

对此的一种快速解决方法是使用Task.Run。对于不支持异步/等待的第三方库,这是一种可接受的解决方法。

答案 1 :(得分:0)

除非您希望在等待同步方法完成之前卸载当前线程以防止其冻结,否则通常使用Task.Run围绕同步方法进行异步包装是一种不好的做法。

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

有关此的更多信息,请参阅this blog