2015-02-23 40 views
0

我有一個MVVM應用程序調用數據服務來獲取一些要綁定的數據。數據服務通過實體框架6訪問SQL Server Compact(v4.0)數據庫。使用實體框架異步方法和SQL Server Compact阻止行爲

數據(當前)需要幾秒鐘才能加載,並在同步調用時(不奇怪)阻止GUI線程。大部分我都假定爲IO綁定,因此我添加了一個等效的Async方法以異步方式執行數據加載,以使GUI保持響應。但是,當我使用EF Async方法時,它看起來沒有什麼區別,GUI線程仍然阻塞,時間大致相同。

我明白,使用異步調用不會將工作移動到不同的線程,但我認爲這個活動的大部分是IO綁定。因此,使用EF異步方法應該允許調用(GUI)線程繼續執行其他工作,但它沒有任何區別。

例如,如果我寫使用EF同步Load方法LoadData方法,則GUI塊,直到數據被加載:

public ObservableCollection<Data> GetData() 
{ 
    //Do IO bound activity... 
    Context.DataTable1.Include(...).Load(); 

    //for demo purposes, just return some data 
    return Context.DataTable1.Local; //(ObservableCollection<Data>) 
} 

的異步方法中加載數據看起來像這樣:

public async Task<ObservableCollection<Data>> GetDataAsync() 
{ 
    //Do IO bound activity... 
    var task = Context.DataTable1.Include(...).LoadAsync(); 
    await task; 

    //for demo purposes, just return some data 
    return Context.DataTable1.Local; //(ObservableCollection<Data>) 
} 

令人驚訝的是(對我來說)我得到了相同的結果,它阻塞了調用線程大致相同的時間長度(我把一個秒錶)。

我開始認爲除了數據庫IO綁定工作之外,可能還有一些導致阻塞的CPU綁定活動的最小數量。於是,我終於嘗試用Task.Run()執行在後臺線程的工作:

public async Task<ObservableCollection<Data>> GetDataAsync() 
{ 
    //Do IO bound activity... 
    Task<ObservableCollection<Competition>> task = Task.Run(async() => 
    { 
     //Do IO bound activity... 
     var task = Context.DataTable1.Include(...).LoadAsync(); 
     await task; 

     //for demo purposes, just return some data 
     return Context.DataTable1.Local; //(ObservableCollection<Data>) 
    }); 
    var result = await task; 
    return result; 
} 

這樣,GUI顯然不會阻止和響應的整個時間。

我讀過圍繞這一切的文章很多,包括什麼時候不(here),何時(here)使用Task.Run職位herehere和博客文章由斯蒂芬·克利裏。我知道我上面的最後一個示例仍然是阻塞的,它只是阻塞了一個線程池線程。我不明白的是,爲什麼在訪問EF異步方法時看起來沒有提供任何好處?

難道是在IO活動正在進行時,還有足夠的CPU綁定工作來導致阻塞?它肯定需要比50ms長得多的響應時間,接近2或3秒才能運行所有查詢,所以這種類型的活動可以開始證明Task.Run的使用是正確的。

或者,我是否寫錯了Async方法,爲什麼它仍然阻塞?

我也想知道是否EF的SQL壓縮提供程序的異步方法是由於某種原因回落到標準的同步調用?

+0

相關:http:// stackoverflow。COM /問題/ 27051169 /爲什麼 - 不 - 等待 - loadasync進行冷凍的-UI-同時,等待任務運行負荷。並非所有的異步方法都是真正的異步方法。它可以做一些微不足道的阻塞操作,有時候會阻止呼叫者很長時間(由於任何原因)。例如'webclient.downloadstringtaskasync'可能會被阻止,因爲它會同步執行Dns查找AFAICR。 – 2015-02-23 14:11:31

+0

SQL Server Compact ADO.NET提供程序不提供任何Async API。但是,加載數據不應該花費幾秒鐘,除非您獲取1000行。在啓動應用程序時初始化dbContext.connection對象,並在應用程序的整個生命週期中保留爲空且未使用。首次使用dbContext初始化的成本也是如此。 – ErikEJ 2015-02-23 16:11:46

+0

感謝@ErikEJ的確認,鑑於我看到的行爲,我想知道是否是這種情況。如果您想將其設置爲答案,我會將其標記爲已回答。 – Jason 2015-02-23 20:34:19

回答

1

SQL Server Compact ADO.NET提供程序不提供任何Async API。但是,加載數據不應該花費幾秒鐘,除非您獲取1000行。在啓動應用程序時初始化dbContext.connection對象,並在應用程序的整個生命週期中保留爲空且未使用。首次使用dbContext初始化的成本也是如此。

+0

所以如果我檢索讓我說30000行,那麼我不得不使用Task.Run來確保這些調用不會阻塞主線程? 我的問題是,我在SQL-CE數據庫之上託管一個本地WCF服務,並且如果在數據庫上執行多個查詢的同時WCF服務開始阻止調用,因爲數據庫看起來像被超載。 有什麼建議可以讓我提高響應速度嗎? – Mike1991 2015-10-02 04:37:58

+0

使用SQL Server Express – ErikEJ 2015-10-02 06:06:12

+0

SQLServer LocalDb或SQLite會成爲一個選項嗎? – Mike1991 2015-10-02 10:52:31

相關問題