- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我们有一个 Windows 服务,可以将一堆插件(程序集)加载到它们自己的 AppDomain 中。每个插件都与 SOA 意义上的“服务边界”对齐,因此负责访问自己的数据库。我们注意到,在单独的 AppDomain 中时,EF 的速度要慢 3 到 5 倍。
我知道 EF 第一次创建 DbContext 并访问数据库时,它必须执行一些必须针对每个 AppDomain 重复的设置工作(即不跨 AppDomain 缓存)。考虑到 EF 代码完全独立于插件(因此独立于 AppDomain),我希望时间与父 AppDomain 的时间相当。它们为什么不同?
已尝试同时针对 .NET 4/EF 4.4 和 .NET 4.5/EF 5。
class Program
{
static void Main(string[] args)
{
var watch = Stopwatch.StartNew();
var context = new Plugin.MyContext();
watch.Stop();
Console.WriteLine("outside plugin - new MyContext() : " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
var posts = context.Posts.FirstOrDefault();
watch.Stop();
Console.WriteLine("outside plugin - FirstOrDefault(): " + watch.ElapsedMilliseconds);
var pluginDll = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + @"..\..\..\EF.Plugin\bin\Debug\EF.Plugin.dll");
var domain = AppDomain.CreateDomain("other");
var plugin = (IPlugin) domain.CreateInstanceFromAndUnwrap(pluginDll, "EF.Plugin.SamplePlugin");
plugin.FirstPost();
Console.ReadLine();
}
}
public interface IPlugin
{
void FirstPost();
}
public class MyContext : DbContext
{
public IDbSet<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
}
public class SamplePlugin : MarshalByRefObject, IPlugin
{
public void FirstPost()
{
var watch = Stopwatch.StartNew();
var context = new MyContext();
watch.Stop();
Console.WriteLine(" inside plugin - new MyContext() : " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
var posts = context.Posts.FirstOrDefault();
watch.Stop();
Console.WriteLine(" inside plugin - FirstOrDefault(): " + watch.ElapsedMilliseconds);
}
}
注意事项:
outside plugin - new MyContext() : 55 outside plugin - FirstOrDefault(): 783 inside plugin - new MyContext() : 352 inside plugin - FirstOrDefault(): 2675
outside plugin - new MyContext() : 53 outside plugin - FirstOrDefault(): 798 inside plugin - new MyContext() : 355 inside plugin - FirstOrDefault(): 2687
outside plugin - new MyContext() : 45 outside plugin - FirstOrDefault(): 778 inside plugin - new MyContext() : 355 inside plugin - FirstOrDefault(): 2683
After some further research in to the cost of AppDomains, there seems to be a suggestion that subsequent AppDomains have to re-JIT system DLLs and so there is an inherent start-up cost in creating an AppDomain. Is that what is happening here? I would have expected that the JIT-ing would have been on AppDomain creation, but perhaps it is EF JIT-ing when it is called?
Reference for re-JIT:http://msdn.microsoft.com/en-us/magazine/cc163655.aspx#S8
Timings sounds similar, but not sure if related:First WCF connection made in new AppDomain is very slow
Based on @Yasser's suggestion that there is EF communication across the AppDomains, I tried to isolate this further. I don't believe this to be the case.
I have completely removed any EF reference from EF.csproj. I now have enough rep to post images, so this is the solution structure:
As you can see, only the plugin has a reference to Entity Framework. I have also verified that only the plugin has a bin folder with an EntityFramework.dll.
I have added a helper to verify if the EF assembly has been loaded in the AppDomain. I have also verified (not shown) that after the call to the database, additional EF assemblies (e.g. dynamic proxy) are also loaded.
So, checking if EF has loaded at various points:
... produces:
Main - IsEFLoaded: FalsePlugin - IsEFLoaded: TruePlugin - new MyContext() : 367Plugin - FirstOrDefault(): 2693Plugin - IsEFLoaded: TrueMain - IsEFLoaded: False
So it seems that the AppDomains are fully isolated (as expected) and the timings are the same inside the plugin.
class Program
{
static void Main(string[] args)
{
var dir = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + @"..\..\..\EF.Plugin\bin\Debug");
var evidence = new Evidence();
var setup = new AppDomainSetup { ApplicationBase = dir };
var domain = AppDomain.CreateDomain("other", evidence, setup);
var pluginDll = Path.Combine(dir, "EF.Plugin.dll");
var plugin = (IPlugin) domain.CreateInstanceFromAndUnwrap(pluginDll, "EF.Plugin.SamplePlugin");
Console.WriteLine("Main - IsEFLoaded: " + Helper.IsEFLoaded());
plugin.FirstPost();
Console.WriteLine("Main - IsEFLoaded: " + Helper.IsEFLoaded());
Console.ReadLine();
}
}
(是的,我不打算为此添加另一个项目......)
public static class Helper
{
public static bool IsEFLoaded()
{
return AppDomain.CurrentDomain
.GetAssemblies()
.Any(a => a.FullName.StartsWith("EntityFramework"));
}
}
public class SamplePlugin : MarshalByRefObject, IPlugin
{
public void FirstPost()
{
Console.WriteLine("Plugin - IsEFLoaded: " + Helper.IsEFLoaded());
var watch = Stopwatch.StartNew();
var context = new MyContext();
watch.Stop();
Console.WriteLine("Plugin - new MyContext() : " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
var posts = context.Posts.FirstOrDefault();
watch.Stop();
Console.WriteLine("Plugin - FirstOrDefault(): " + watch.ElapsedMilliseconds);
Console.WriteLine("Plugin - IsEFLoaded: " + Helper.IsEFLoaded());
}
}
@Yasser:System.Data.Entity 仅在访问数据库后加载到插件中。最初只有 EntityFramework.dll 被加载到插件中,但数据库后其他 EF 程序集也被加载:
Zipped solution .该站点仅将文件保留 30 天。欢迎推荐更好的文件共享网站。
此外,我很想知道您是否可以通过在主项目中引用 EF 来验证我的发现,并查看原始样本的计时模式是否可重现。
需要明确的是,我感兴趣的是首次调用时间分析,其中包括 EF 启动。在第一次调用时,从父 AppDomain 中的 ~800ms 到子 AppDomain 中的 ~2700ms 是非常明显的。在后续调用中,从 ~1ms 到 ~3ms 几乎不会引起注意。为什么第一次调用(包括 EF 启动)在子 AppDomains 中的成本要高得多?
我更新了示例以仅关注 FirstOrDefault()
调用以减少噪音。在父 AppDomain 中运行和在 3 个子 AppDomain 中运行的一些时间安排:
EF.vshost.exe|0|FirstOrDefault(): 768EF.vshost.exe|1|FirstOrDefault(): 1EF.vshost.exe|2|FirstOrDefault(): 1AppDomain0|0|FirstOrDefault(): 2623AppDomain0|1|FirstOrDefault(): 2AppDomain0|2|FirstOrDefault(): 1AppDomain1|0|FirstOrDefault(): 2669AppDomain1|1|FirstOrDefault(): 2AppDomain1|2|FirstOrDefault(): 1AppDomain2|0|FirstOrDefault(): 2760AppDomain2|1|FirstOrDefault(): 3AppDomain2|2|FirstOrDefault(): 1
static void Main(string[] args)
{
var mainPlugin = new SamplePlugin();
for (var i = 0; i < 3; i++)
mainPlugin.Do(i);
Console.WriteLine();
for (var i = 0; i < 3; i++)
{
var plugin = CreatePluginForAppDomain("AppDomain" + i);
for (var j = 0; j < 3; j++)
plugin.Do(j);
Console.WriteLine();
}
Console.ReadLine();
}
private static IPlugin CreatePluginForAppDomain(string appDomainName)
{
var dir = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + @"..\..\..\EF.Plugin\bin\Debug");
var evidence = new Evidence();
var setup = new AppDomainSetup { ApplicationBase = dir };
var domain = AppDomain.CreateDomain(appDomainName, evidence, setup);
var pluginDll = Path.Combine(dir, "EF.Plugin.dll");
return (IPlugin) domain.CreateInstanceFromAndUnwrap(pluginDll, "EF.Plugin.SamplePlugin");
}
public class SamplePlugin : MarshalByRefObject, IPlugin
{
public void Do(int i)
{
var context = new MyContext();
var watch = Stopwatch.StartNew();
var posts = context.Posts.FirstOrDefault();
watch.Stop();
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "|" + i + "|FirstOrDefault(): " + watch.ElapsedMilliseconds);
}
}
Zipped solution .该站点仅将文件保留 30 天。欢迎推荐更好的文件共享网站。
最佳答案
这似乎只是子 AppDomain 的成本。 rather ancient post (这可能不再相关)表明除了必须对每个子 AppDomain 进行 JIT 编译之外,可能还有其他考虑因素,例如评估安全政策。
Entity Framework 确实具有相对较高的启动成本,因此效果被放大了,但是对于比较调用 System.Data 的其他部分(例如直接的 SqlDataReader
)同样可怕:
EF.vshost.exe|0|SqlDataReader: 67EF.vshost.exe|1|SqlDataReader: 0EF.vshost.exe|2|SqlDataReader: 0AppDomain0|0|SqlDataReader: 313AppDomain0|1|SqlDataReader: 2AppDomain0|2|SqlDataReader: 0AppDomain1|0|SqlDataReader: 290AppDomain1|1|SqlDataReader: 3AppDomain1|2|SqlDataReader: 0AppDomain2|0|SqlDataReader: 316AppDomain2|1|SqlDataReader: 2AppDomain2|2|SqlDataReader: 0
public class SamplePlugin : MarshalByRefObject, IPlugin
{
public void Do(int i)
{
var watch = Stopwatch.StartNew();
using (var connection = new SqlConnection("Data Source=.\\sqlexpress;Initial Catalog=EF.Plugin.MyContext;Integrated Security=true"))
{
var command = new SqlCommand("SELECT * from Posts;", connection);
connection.Open();
var reader = command.ExecuteReader();
reader.Close();
}
watch.Stop();
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "|" + i + "|SqlDataReader: " + watch.ElapsedMilliseconds);
}
}
即使新建一个不起眼的 DataTable
也会膨胀:
EF.vshost.exe|0|DataTable: 0EF.vshost.exe|1|DataTable: 0EF.vshost.exe|2|DataTable: 0AppDomain0|0|DataTable: 12AppDomain0|1|DataTable: 0AppDomain0|2|DataTable: 0AppDomain1|0|DataTable: 11AppDomain1|1|DataTable: 0AppDomain1|2|DataTable: 0AppDomain2|0|DataTable: 10AppDomain2|1|DataTable: 0AppDomain2|2|DataTable: 0
public class SamplePlugin : MarshalByRefObject, IPlugin
{
public void Do(int i)
{
var watch = Stopwatch.StartNew();
var table = new DataTable("");
watch.Stop();
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "|" + i + "|DataTable: " + watch.ElapsedMilliseconds);
}
}
关于c# - 为什么 Entity Framework 在不同的 AppDomain 中运行时速度明显变慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18456491/
我有这些实体(这只是我为这篇文章创建的抽象): 语言 区 说明 这些是它们之间的引用: 区 * - 1 语言 说明 * - 1 语言 区 1 - 1 说明 如果我这样取: var myFetch =
经过大量谷歌搜索后,除了降级 hibernate 版本之外,我没有找到问题的答案。但我在 2003 年类似的帖子中遇到了这种情况。 问题是什么: //in the first session I d
我听说过 linq to entities 。 Entity Framework 是利用linq to entities吗? 最佳答案 LINQ to Entities 是 Entity Framew
我是 Entity Framework 和 ASP.Net MVC 的新手,主要从教程中学习,对任何一个都没有深入了解。 (我确实有 .Net 2.0、ADO.Net 和 WebForms 方面的经验
如果我编写 LINQ to Entities 查询,该查询是否会转换为提供程序理解的 native 查询(即 SqlClient)? 或者 它是否会转换为实体 SQL,然后 Entity Framew
这个问题已经有答案了: EF: Include with where clause [duplicate] (5 个回答) 已关闭 2 年前。 看来我无法从数据库中获取父级及其子级的子集。 例如...
我开始在一家新公司工作,我必须在一个旧项目上使用 C++ 工作。所以,我忘记了一些 C++ 本身的代码结构。在一个函数中,我在一个函数中有双冒号::,但我不知道如何理解它。 例如,我知道如果我有 EN
我写了一个方法来允许为 orderby 子句传递一个表达式,但我遇到了这个问题。 Unable to cast the type 'System.DateTime' to type 'System.I
简单的问题:LINQ to Entities 和 Entity Framework 有什么区别?到目前为止,我认为这两个名称是用来描述同一个查询的,但我开始觉得事实并非如此。 最佳答案 Entity
我想使用 Entity Framework 。但是,我还要求允许我的用户在我们的系统中定义自定义字段。我想仍然使用 Entity Framework ,而不是使用具有哈希表属性的分部类。 下面是我想到
我正在阅读这个 E.F. 团队博客的这个系列 http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-featu
我正在使用 EF6 开发插件应用程序,代码优先。 我有一个名为 User 的实体的主要上下文。 : public class MainDataContext : DbContext { pub
当我得到最后的 .edmx 时,我遇到了问题。 我收到一条消息说 错误 11007:未映射实体类型“pl_Micro”。 查看设计器 View ,我确实看到该表确实存在。 我怎样才能克服这个消息? 最
我已阅读与使用 Entity Framework 时在 Linq to Entities (.NET 3.5) 中实现等效的 LEFT OUTER JOIN 相关的所有帖子,但尚未找到解决以下问题的方
使用 WCF RIA 服务和 Entity Framework 4. 我有 3 个 DTO:学校、州、区。 州 DTO 有一个地区属性(property),其构成。学校 DTO 有一个国家属性(pro
我有一个 Employee 实体,它继承自一个继承自 Resource 实体(Employee -> Person -> Resource)的 Person 实体。是否可以通过编程方式获取 Emplo
我有一个使用 JPA 的 java 应用程序。 假设我有一个名为 Product 的实体与 name和 price属性(所有实体都有一个 id 属性)。 自然我可以得到一个List相当容易(来自查询或
我有一个 Entity Framework 类,其中有两个指向另一个对象的引用 public class Review { [Key] public int Id {get;s
我是 Symfony 2 的新手,我想知道一些事情: 假设我的项目中有 2 个 bundle 。我想在两个包中使用从我的数据库生成的实体。 我应该在哪里生成实体? (对我来说,最好的方法是在 bund
我想在具有方法和属性的部分类中扩展 EF 实体。我经常这样做。 但是现在我需要将来自该实体的数据与来自其他实体的数据结合起来。因此,我需要能够访问实体 objectcontext(如果附加)来进行这些
我是一名优秀的程序员,十分优秀!