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