2015-05-19 117 views
0

所以..这可能是一个愚蠢的问题。使用EF6异步会提高性能VS在一个任务包同步EF6电话(假定数据库调用是一个Web API REST API方法内)异步EF 6 vs包装同步EF

即我不能让我的头完全围绕WHY,为什么是这样的:

//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这似乎是说(简单化)“不要只W¯¯说唱同步方法,更有效地重写方法“。

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

问题2(和我真正的问题) - 可以有人解释为什么这样比较好?在数据库操作完成之前,两种实现都不会导致释放请求线程来处理其他请求吗?

回答

5

比方说,你正在烘烤一个大的节日晚餐。将会有大量的食物,包括一个大鸡的主菜。烹饪需要很长时间,所以你先准备好,然后把它放入烤箱中,然后设定一个计时器以便稍后再检查它,然后继续准备下一道菜(土豆泥)。

你不能坐在那里等待(同步)那只鸡完成;你需要让它做饭(异步),而你去准备所有其他的菜肴。如果您在开始其他任何事情之前等待鸡完成,除了您超级无聊之外,当您完成其他所有事情时,鸡肉会变得冰冷。

现在有几种方法可以使您在做其他工作时进行此操作(让鸡肉做饭)。例如,您可以设置一个计时器并在计时器通知您时间到了之后立即检查计时器。另一个解决方案是不能自己工作。你可以去抓你的儿子,让他坐在炉子前面等待鸡准备好,让他在准备好时通知你。

使用计时器类似于单线程异步解决方案。 (每个人都是一个线程)。只有一个工作者(你),并且你开始异步工作,在需要做事情时有异步通知,但是一次只处理一件事情。厨房中有多个人类似于多线程应用程序。如果你使用这些多人来真正完成多项任务,而这些任务需要一个真正的人同时工作(比如说,当你的儿子在洗芦笋时你正在捣烂土豆),那么你就完成了你的工作更快。当你使用那个额外的人(线程)不做任何事情,而是坐在那里等待某件事完成时,当你离开工作时,那么你只是在浪费那个人的(线程)时间。他们宁愿离开,做一些有成效的事情。

因此,要完全剥离类比,当您使用Task.Run同步执行IO时,您正在线程池中调度工作,分配的线程只需要坐在那里无所事事(而不是做实际的工作)等待IO完成。当你只使用固有的异步IO操作时,根本没有其他线程参与

+0

非常好的比喻。 – juharr

+0

感谢您的回答和类比。说得通。但是,EF6异步方法(ToListAsync)*固有地*异步?是否因为他们在实现中使用异步I/O? – HokieMike

+0

@HokieMike是的。就其本质而言,IO几乎总是异步的。几乎任何时候你看到同步IO方法都意味着,某个地方出于某种原因*会异步阻塞,直到异步通知表明它可以继续。许多IO操作的API都不愿意隐藏固有的异步;但现在它在C#中变得越来越常见,以便将异步地显示给调用者。 – Servy