使用Task.Run进行服务中的同步方法

时间:2016-06-30 07:32:48

标签: c# asynchronous task-parallel-library task

我读过很多关于异步编程的文章,但我不确定一件事。我有第三方winrt库,用C ++编写,我想包装它。所以现在我有:

public Task LoginAsync(){
return Task.Run(winrtLibrary.Login();)
}

根据Stephen Cleary和Stephen Toub的博客,这不是一个好的解决方案。但是当我同步使用该方法时,我的UI将无法响应并将被阻止。 是否更好地同步公开服务方法并在UI中使用Task.Run?

1 个答案:

答案 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的替代方法是一种更好的方法,它遵循清洁代码的原则。