这两个EF中的异步调用有什么区别?

5

我看到EF6中有一个新的功能,即异步方法。我找到了一个例子。

第一种方式是普通调用,例如使用EF5:

public Store FindClosestStore(DbGeography location)
{
    using (var context = new StoreContext())
    {
        return (from s in context.Stores
           orderby s.Location.Distance(location)
           select s).First();
    }
}

在EF6中,新增了异步方法的调用方式。

public async Task<Store> FindClosestStore(DbGeography location)
{
    using (var context = new StoreContext())
    {
        return await (from s in context.Stores
            orderby s.Location.Distance(location)
            select s).FirstAsync();
    }
}

然而,我可以执行以下操作(语法大约如下,我是凭记忆做的):
public async Task<Store> MyAsyncMethod(DbGeography location)
{
     return await Task.Run(() => FindClosestStore());
}

我的意思是,我可以使用Task.Run调用第一个方法(不是异步的),等待结果。目前,这是我调用任何方法(不仅仅是EF)的异步调用方式。这也是一个异步调用吗?或者只有当我使用EF6异步方法时才是真正的异步调用?

为什么需要在新版本的EF6中使用异步方法?仅仅是为了简化吗?


async和await是.NET 4.5中的新语法糖,你可以使用Task with ContinueWith完成相同的操作。 - Hamlet Hakobyan
1个回答

9
这里的区别在于代码等待的方式。
在这段代码中:
public async Task<Store> FindClosestStore(DbGeography location)
{
    using (var context = new StoreContext())
    {
        return await (from s in context.Stores
            orderby s.Location.Distance(location)
            select s).FirstAsync();
    }
}

EF将向数据库发出查询,并返回结果。

一旦结果返回,任务将完成并且await块将继续执行。

也就是说,.NET本身没有等待响应的线程。希望在DB驱动程序中有更低级别的回调通知.NET当结果到达。

(这至少是.NET中其他异步IO工作的方式,我假设ADO.NET异步也是如此)

另一种情况:

public async Task<Store> MyAsyncMethod(DbGeography location)
{
     return await Task.Run(()=> FindClosestStore());
}

会有一个线程等待来自数据库的响应。也就是说,您将拥有阻塞IO,但使用task.run技巧可以隐藏它。

对于消费者来说,这两种情况都会表现相同,区别在于您在最后一个示例中占用了资源。


我认为使用async/await可以避免使用新线程的需要。有时会创建,有时不会(取决于情况)。实际上,在WCF中,使用async/await模式释放资源,同时服务请求。在EF中,它是否能够以同样的方式工作,即在请求执行时释放资源? - Álvaro García
2
在最后的代码示例中,将会有一个阻塞线程,因为它使用了非异步 EF 方法。即使您将该调用包装在 async/await 块中,也是如此。也就是说,“FindClosestStore()”将在幕后阻塞一个线程。 - Roger Johansson
在使用异步/等待时,WCF中是否会出现这种情况?有没有办法在EF5中使用异步? - Álvaro García

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接