EF速度优化

为什么Entity Framework的初始化速度慢如蜗牛呢?

对于在应用程序中定义的每个DbContext类型,在首次使用时,Entity Framework都会根据数据库中的信息在内存生成一个映射视图(mapping views),而这个操作非常耗时。

方法一

[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. using (var dbcontext = new JuCheapDbContext())  
  2. {  
  3.     //to do somethings  
  4. }  

比如上面的代码,在第1次调用JuCheapDbContext进行数据库操作时会进行缓慢的mapping views生成操作,后续的JuCheapDbContext操作会共享已经生成的mapping views,不受这个问题影响。但是要注意的是你定义的每一个DbContext都会面临这个问题。

而我们的缓解之道则是在应用程序初始化时一次性触发所有的DbContext进行mapping views的生成操作——调用StorageMappingItemCollection的GenerateViews()方法。

代码如下(Entity Framework的版本至少是6.0才支持):

[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. using (var dbcontext = new JuCheapDbContext())  
  2. {  
  3.     var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;  
  4.     var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);  
  5.     mappingCollection.GenerateViews(new List<EdmSchemaError>());  
  6. }  
  7.   
  8. //对程序中定义的所有DbContext逐一进行这个操作  
[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. using (var dbcontext = new JuCheapDbContext())  
  2. {  
  3.     //to do somethings  
  4. }  

比如上面的代码,在第1次调用JuCheapDbContext进行数据库操作时会进行缓慢的mapping views生成操作,后续的JuCheapDbContext操作会共享已经生成的mapping views,不受这个问题影响。但是要注意的是你定义的每一个DbContext都会面临这个问题。

而我们的缓解之道则是在应用程序初始化时一次性触发所有的DbContext进行mapping views的生成操作——调用StorageMappingItemCollection的GenerateViews()方法。

代码如下(Entity Framework的版本至少是6.0才支持):

[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. using (var dbcontext = new JuCheapDbContext())  
  2. {  
  3.     var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;  
  4.     var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);  
  5.     mappingCollection.GenerateViews(new List<EdmSchemaError>());  
  6. }  
  7.   
  8. //对程序中定义的所有DbContext逐一进行这个操作  

方法二  NGen优化

相关优化可以查看这篇文章Improving Startup Performance with NGen (EF6 Onwards),下面这条方法,主要是针对EF6及以上版本的,因为低于这个版本的自带该特性,在这篇文章里说的很清楚“在6.0之前的EF中,EF的运行时核心类库也是.NET框架的一部分,其本地映像在.NET 核心类库加载时自动加载,在6.0及之后的版本,EF整个运行时已经被集成到EntityFramework NuGet包中,本地映像需要使用NGen工具来生成才能达到类似的效果”。

提到这里,首先要说一下NGen这个工具的作用以及为什么能够加快应用程序的启动性能。.NET 框架支持为托管应用或者程序集生成本地映像文件来帮助应用程序更快启动和在一些情况下减少内存占用。在应用程序执行之前,通过将托管代码程序集翻译为包含本地机器指令的文件,能够减少.NET JIT编译器在应用程序启动的时候,生成本地指令代码这一过程,从而能够加快应用程序启动。

使用NGen也很简单

1:以管理员身份启动控制台cmd程序

2:切换到本机.NET 工具目录下:

   对于32位机器,通常在%WINDIR%\Microsoft.NET\Framework\v4.0.30319\下

   对于64位机器,通常在 %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\下

3:然后执行 ngen install 加上程序集的路径和名称,即可。

比如在我的机器上,可以看到如下:

NGen

经过这一操作,首次访问db的速度终于控制到了500ms以内。

以上是EF的优化,解决了首次部署之后,第一次访问数据库的问题,对于应用程序放置一会儿,再次请求由于线程池回收导致再次访问变慢的问题,通过设置IIS解决。

三、IIS设置

将服务或者站点部署到IIS上之后,在对应的线程池里有两个地方可以设置,如下图:

IIS设置

  • 空闲超时时间,默认是20分钟,表示在20分钟之类,如果没有请求进来,那么对应的线程就处于闲置状态,这里将其改为0。
  • 例常(Regular)回收时间,这里默认为1740分钟,大概是29个小时(为什么是29而不是24,据说是为了将回收时间的影响减小到最小化,方便调试找到问题,29是24以后的第一个质数),表示大概每隔29个小时,IIS会回收一次应用程序线程池里面的线程。

这样设置之后就可以解决第二个问题。

 

四、总结

本文简单介绍了优化EntityFramework初次启动速度的方法,以及为防止IIS线程超时闲置,以及例常线程回收导致的初次运行时间过长的解决方法,希望对您解决上述问题有所帮助。





没有更多推荐了,返回首页