简体   繁体   English

使用Entity Framework Async方法和SQL Server Compact阻止行为

[英]Blocking behaviour with Entity Framework Async methods and SQL Server Compact

I have an MVVM app that calls a data service to get some data to bind. 我有一个MVVM应用程序,该应用程序调用数据服务以获取一些要绑定的数据。 The data service accesses a SQL Server Compact (v4.0) database through Entity Framework 6. 数据服务通过实体框架6访问SQL Server Compact(v4.0)数据库。

The data (currently) takes a few seconds to be loaded and when called synchronously this (not surprisingly) blocks the GUI thread. 数据(当前)需要几秒钟的时间加载,并且在同步调用时,这(不足为奇)会阻塞GUI线程。 Most of this I had assumed to be IO bound so I added an equivalent Async method to execute the data load in an asynchronous fashion to allow the GUI to remain responsive. 我假设其中大多数都是受IO约束的,所以我添加了等效的Async方法以异步方式执行数据加载,以使GUI保持响应。 However when I make use of the EF Async methods, it doesn't appear to make any difference, the GUI thread still blocks, for roughly the same amount of time. 但是,当我使用EF Async方法时,似乎没有什么区别,GUI线程仍会阻塞大约相同的时间。

I understand that using the Async calls will not move the work to a different thread, however I had assumed the majority of this activity to be IO bound. 我知道使用Async调用不会将工作移到另一个线程,但是我已经假定此活动的大部分是IO绑定的。 Hence using the EF Async methods should allowing the calling (GUI) thread to continue doing other work, but it is not making any difference. 因此,使用EF异步方法应允许调用(GUI)线程继续执行其他工作,但没有任何区别。

For example if I write the LoadData method to use the EF synchronous Load method, then the GUI blocks until the data is loaded: 例如,如果我编写LoadData方法以使用EF同步Load方法,则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>)
}

The Async method to load the data looks like this: 加载数据的Async方法如下所示:

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>)
}

Surprisingly (for me) I get the same result and it blocks the calling thread for roughly the same length of time (I put a stopwatch on it). 出乎意料的是(对我而言),我得到的结果是相同的,并且它在大致相同的时间内阻塞了调用线程(我在上面放了一块秒表)。

I started thinking that in addition to the database IO bound work, there may be some minimum amount of CPU bound activity that is causing the blocking. 我开始认为,除了数据库IO绑定工作之外,可能还有一些最小数量的CPU绑定活动正在引起阻塞。 So I finally tried executing the work on a background thread by using Task.Run(): 所以我最终尝试使用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;
}

With this, the GUI obviously doesn't block and is responsive the entire time. 这样,GUI显然不会被阻塞,并且在整个时间段内都响应。

I've read many articles all around this, including posts here and here and blog posts by Stephen Cleary about when not to ( here ) and when to ( here ) use Task.Run. 我读过围绕这一切的许多文章,包括职位在这里这里和博客文章由斯蒂芬·克利里约时,不要( 在这里 ),何时( 这里 )使用Task.Run。 I understand that my last example above is still blocking, it is just blocking a threadpool thread. 我知道我上面的最后一个示例仍在阻塞,它只是在阻塞线程池线程。 What I don't understand really is, why when accessing the EF async methods does it not appear to be providing any benefit? 我真正不了解的是,为什么在访问EF异步方法时它似乎没有提供任何好处?

Could it be that whilst there is IO activity going on, there is also sufficient CPU bound work to cause the blocking? 可能是尽管正在进行IO活动,但同时也有足够的CPU绑定工作导致阻塞? It is certainly taking significantly longer than 50ms to respond, closer to 2 or 3 seconds to run all the queries, so this type of activity can start justifying the use of the Task.Run? 当然,响应所需的时间明显超过50毫秒,而运行所有查询的时间将接近2或3秒,因此这种类型的活动可以开始证明使用Task.Run是合理的。

Or, have I written the Async method incorrectly, hence why it is still blocking? 还是我写的Async方法不正确,所以为什么它仍然阻塞?

I also wondered if perhaps the Async methods for the SQL Compact provider for EF were for some reason falling back to the standard synchronous calls? 我还想知道是否可能由于某种原因而使EF的SQL Compact提供程序的Async方法回退到标准的同步调用?

The SQL Server Compact ADO.NET provider does not provide any Async APIs. SQL Server Compact ADO.NET提供程序不提供任何异步API。 But loading data should never take a fewcseconds, unless you are fetching 1000s of rows. 但是,除非要获取1000的行,否则加载数据的时间绝对不要花几秒钟。 Initialize a dbContext.connection object when you start your app, and leave empty and unused for the lifetime of your app. 启动应用程序时初始化dbContext.connection对象,并在应用程序的生命周期内保留为空且未使用。 There is also a cost of init of dbContext first time. 第一次初始化dbContext也有代价。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM