【问题标题】:Async EF 6 vs wrapped Sync EF异步 EF 6 与打包的同步 EF
【发布时间】:2015-05-19 17:23:28
【问题描述】:

所以.. 这可能是一个愚蠢的问题。我无法完全理解 WHY 使用 EF6 Async 与将同步 EF6 调用包装在 Task 中相比会提高性能(假设 db 调用在 Web API REST api 方法中)

即,为什么会这样:

//wrapping synch with asynch
return await Task.Run(() =>
{
    var albums = this.context.Albums
                .Where(x => x.Artist.ID == artist.ID)
                .ToList();
    return albums;
});

比这更糟糕:

//using async 
return await this.context.Albums
            .Where(x => x.Artist.ID == artist.ID)
            .ToListAsync();

注意:我已经读过这篇文章 http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx,它似乎在说(过于简单化)“不要只包装同步方法,更有效地重写方法”。

问题 1,这是 EF6 异步实现所做的吗?我假设它在实现中使用了异步 I/O?

问题 2(也是我真正的问题) - 有人可以解释 WHY 这更好吗?在 db 操作完成之前,这两种实现不会释放请求线程来处理其他请求吗?

【问题讨论】:

    标签: c# entity-framework asynchronous


    【解决方案1】:

    假设您正在烤一顿丰盛的节日晚餐。会有很多食物,包括一只大鸡的主菜。烹饪需要很长时间,所以你提前准备好并放入烤箱,设置一个计时器稍后再检查,然后继续准备下一道菜(土豆泥)。

    您不能只是坐在那里(同步地)等待那只鸡吃完;您需要在准备所有其他菜肴时让它(异步)烹饪。如果你等鸡吃完再开始做其他事情,除了你超级无聊之外,当你做完其他所有事情时,鸡会变冷。

    现在有几种方法可以让您在进行其他工作的同时进行此操作(让鸡肉煮熟)。例如,您可以设置一个计时器,并在计时器通知您时间到时立即检查它。另一种解决方案是不要自己工作。你可以去抓住你的儿子,告诉他就坐在炉子前等着鸡肉准备好,让他在准备好的时候通知你。

    使用计时器类似于单线程异步解决方案。 (每个人都是一个线程。)只有一个工人(你),你开始异步工作,当你需要做某事时有异步通知,但一次只做一件事。厨房里有多个人类似于多线程应用程序。如果您使用这些多人来实际执行需要一个实际人员同时工作的多项任务(例如,您正在捣土豆,而您的儿子正在洗芦笋),那么您就完成了工作快点。当您使用那个额外的人(线程)什么都不做,只是坐在那里等待完成,而您去工作时,那么您只是在浪费那个人(线程)的时间;他们宁愿出去做一些富有成效的事情。

    因此,为了完全消除类比,当您使用 Task.Run 同步执行 IO 时,您是在线程池中调度工作,分配的线程需要坐在那里什么都不做(而不是做实际的生产性工作),而它等待 IO 完成。当您只使用固有的异步 IO 操作时,根本不涉及其他线程

    【讨论】:

    • 感谢您的回答和类比。说得通。但是,EF6 异步方法 (ToListAsync) inherently 究竟是如何异步的?是因为他们在实现中使用了异步 I/O?
    • @HokieMike 是的。 IO,就其本质而言,几乎总是异步的。几乎任何时候你看到同步 IO 方法都意味着某处的某些东西不妨碍同步阻塞,直到异步通知说它可以继续。许多 IO 操作的 API 不遗余力地隐藏固有的异步性;但现在在 C# 中将这种异步实际暴露给调用者变得越来越普遍。
    猜你喜欢
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 1970-01-01
    • 2014-07-04
    • 2020-01-18
    相关资源
    最近更新 更多