2016-06-30 54 views
5

我讀過很多關於異步編程的文章,但我不確定是否有一件事。我有第三方winrt庫,用C++編寫,我想包裝它。所以現在我有:在服務中使用Task.Run作爲同步方法

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

根據斯蒂芬·克利裏和Stephen Toub的博客,這不是很好的解決方案。但是當我同步使用該方法時,我的用戶界面不會響應並且會被阻止。 在UI中使用Task.Run是否更好地公開服務方法?

+0

該方法有什麼作用?長時間阻擋你的用戶界面的東西?那麼答案是肯定的,開始一個新的任務。 –

+0

是的,登錄方法可以長時間運行。這取決於網絡等。如果我阻止用戶界面,我不能取消登錄過程。 – JuP

+1

斯蒂芬·克利裏提出的觀點是'Task.Run'「浪費了」一個線程來完成工作,而線程是昂貴的。然而你的C++庫需要一個線程來工作。所以問題不在於Task.Run是邪惡的。但是'Task.Run'通常隱藏了依賴線程的問題。 – Aron

回答

3

斯蒂芬Toub指

什麼

不要在方法的實現中使用Task.Run;相反,使用Task.Run調用方法

是你不應該使用Task.Run躲在異步方法(Task返回方法)CPU限制的工作。如果您需要封裝外部代碼,請將其隱藏在反映此代碼所執行操作的界面之後。任何異步I/O都可以(也應該)作爲Task返回方法公開,並且CPU綁定的工作必須通過適當的API公開。讓代碼的使用者自己決定如何使用該代碼。當你也碰到消費者時,使用Task.Run來運行你的同步代碼(現在通過界面進行包裝和顯示)其中非常清楚你正在卸載CPU綁定工作。例如,在UI應用程序中,您應該在UI層調用Task.Run(而不是深入BL或甚至DA層),這非常清楚,UI可以卸載一些CPU綁定的工作。


爲什麼你覺得,我不應該叫Task.Run在BL?如果我有 ViewModel,它引用BL和BL引用服務層(在我的 的情況下是它的包裝)。

我認爲方法簽名應該完全反映方法的作用。 我能做的最好的就是你重定向回Cleary's article

當開發人員看到一個API winrtLibrary.Login()和winrtLibrary.LoginAsync()的兩個方法,的約定是,它代表了自然 - 異步 操作。換句話說,開發人員希望winrtLibrary.LoginAsync()是「自然」實現的 ,而winrtLibrary.Login()基本上是該操作的同步(阻塞)等效操作的 。該API意味着 winrtLibrary.Login在某些時候會讓調用線程進入等待狀態 ,因爲它會阻止自然異步操作到 完成。

您仍然可以躲在異步方法同步碼,並按照經驗克利的規則,如果你簽上你的方法public Task OffloadLoginToTheThreadPool()。但我認爲(而且顯然也是Cleary),從UI(或Controller)簡單調用Task.Run的替代方法是一種更好的方法,它遵循Clean Code的原則。

+0

爲什麼你認爲我不應該在BL中調用Task.Run?如果我有ViewModel,它引用BL和BL引用服務層(在我的情況是它的包裝)。 – JuP

相關問題