2013-05-17 110 views
2
public class MyClass 
{ 
    MyEntities db = new MyEntities(); 

    public MyClass() 
    { 
     this.Initialise(); // Does not return immediately. Why? 
    } 

    private async void Initialise(); 
    { 
     await this.db.Entities.LoadAsync(); 
    } 
} 

如果我更改Initialise使用await Task.Run()來調用同步this.db.Entities.Load()然後它立即返回如預期。async void方法不立即返回(EF6)

+1

在附註上,最好避免使用「async void」。我在我的博客上有一些[用於'async'初始化的替代方法](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html)。 –

+0

該類是一個視圖模型,因此包含視圖的其他狀態信息,例如是否啓用按鈕。我需要立即返回構造對象,否則視圖將處於未定義狀態。 async方法只是填充構建viewmodel時已綁定的屬性,並且數據異步出現在屏幕上。由於它是一個WPF應用程序,異常將會在UI線程的同步上下文中捕獲(與Windows Phone/Windows 8 Store應用程序不同)。 – Monstieur

+1

我明白並重申我的建議,即使用異步初始化方法。與'async void'唯一的區別是,你可以正確處理錯誤(甚至可以通過數據綁定處理異常情況)。 WP和Win8應用程序與WPF具有相同的「async void」異常處理,它會在UI線程的SyncContext中引發。但是,如果您處理例外情況,那麼您正在爲本地問題應用全局解決方案。 –

回答

5

代碼將執行到第一個等待點(對於尚未完成的數據)。請記住,Initialise是有效的:

var tmp = this.db.Entities.LoadAsync(); 
await tmp; 

因此,我們必須得出結論,LoadAsync了一段不平凡的量就產生了。這在API限制範圍內 - await API僅有助於使事情等待;它並不保證所有內容都是非阻塞的。例如,下面是完全awaitable:

static Task<int> Evil() { 
    Thread.Sleep(60000); 
    return Task.FromResult(4); 
} 

這可能是因爲該數據上下文被加載的元數據,加載組件,等等 - 它知道它是否可以產生之前。

+0

我認爲延遲是由於實體框架第一次使用DbContext實例時發生的。 LoadAsync()方法可能只是異步執行數據庫I/O。預熱比我的應用程序中的任何數據庫查詢都要長得多。唯一的解決方案是在完整的Task.Run()中執行「預熱查詢」,然後使用await執行後續的Async方法。 – Monstieur