我讀過很多關於異步編程的文章,但我不確定是否有一件事。我有第三方winrt庫,用C++編寫,我想包裝它。所以現在我有:在服務中使用Task.Run作爲同步方法
public Task LoginAsync(){
return Task.Run(winrtLibrary.Login();)
}
根據斯蒂芬·克利裏和Stephen Toub的博客,這不是很好的解決方案。但是當我同步使用該方法時,我的用戶界面不會響應並且會被阻止。 在UI中使用Task.Run是否更好地公開服務方法?
我讀過很多關於異步編程的文章,但我不確定是否有一件事。我有第三方winrt庫,用C++編寫,我想包裝它。所以現在我有:在服務中使用Task.Run作爲同步方法
public Task LoginAsync(){
return Task.Run(winrtLibrary.Login();)
}
根據斯蒂芬·克利裏和Stephen Toub的博客,這不是很好的解決方案。但是當我同步使用該方法時,我的用戶界面不會響應並且會被阻止。 在UI中使用Task.Run是否更好地公開服務方法?
斯蒂芬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的原則。
爲什麼你認爲我不應該在BL中調用Task.Run?如果我有ViewModel,它引用BL和BL引用服務層(在我的情況是它的包裝)。 – JuP
該方法有什麼作用?長時間阻擋你的用戶界面的東西?那麼答案是肯定的,開始一個新的任務。 –
是的,登錄方法可以長時間運行。這取決於網絡等。如果我阻止用戶界面,我不能取消登錄過程。 – JuP
斯蒂芬·克利裏提出的觀點是'Task.Run'「浪費了」一個線程來完成工作,而線程是昂貴的。然而你的C++庫需要一個線程來工作。所以問題不在於Task.Run是邪惡的。但是'Task.Run'通常隱藏了依賴線程的問題。 – Aron