我读过很多关于异步编程的文章,但我不确定一件事。我有第三方winrt库,用C ++编写,我想包装它。所以现在我有:
public Task LoginAsync(){
return Task.Run(winrtLibrary.Login();)
}
根据Stephen Cleary和Stephen Toub的博客,这不是一个好的解决方案。但是当我同步使用该方法时,我的UI将无法响应并将被阻止。 是否更好地同步公开服务方法并在UI中使用Task.Run?
答案 0 :(得分:4)
Stephen Toub的意思
在方法的实现中不要使用Task.Run;相反,使用Task.Run来调用方法
是不是你不应该使用Task.Run
来隐藏异步方法(Task
返回方法)背后的CPU绑定工作。如果需要包装外部代码,请将其隐藏在反映此代码功能的界面后面。任何异步I / O都可以(并且应该)作为Task
返回方法公开,并且必须使用适当的API公开CPU绑定工作。让代码的使用者自己决定如何使用该代码。当您遇到消费者时,请使用Task.Run
来运行您的同步代码(现在通过界面包装并公开)非常清楚您正在卸载CPU绑定工作。例如,在UI应用程序中,您应该在UI层中调用Task.Run
(而不是在BL或甚至DA层中深入调用),其中非常清楚UI会卸载一些CPU绑定的工作。
为什么你认为我不应该在BL中调用Task.Run?如果我有 ViewModel,引用BL和BL引用服务层(在我的 case是包装)。
我认为方法签名应该准确反映该方法的作用。 我能做的最好的事情是将你重定向回Cleary's article:
当开发人员在API winrtLibrary.Login()和winrtLibrary.LoginAsync()中看到两个方法时,的约定是它们代表一个自然异步 操作即可。换句话说,开发人员期望winrtLibrary.LoginAsync()是 “自然”实现和winrtLibrary.Login()本质上是一个 同步(阻塞)等效的操作。该API意味着 winrtLibrary.Login会在某个时刻让调用线程进入等待状态 状态,因为它阻止自然异步操作 完整。
如果您将方法指定为public Task OffloadLoginToTheThreadPool()
,您仍然可以隐藏异步方法背后的同步代码并遵循Cleary的经验法则。但我认为(显然也是Cleary)只是从UI(或Controller)调用Task.Run
的替代方法是一种更好的方法,它遵循清洁代码的原则。