我们注意到一些非常小的网络服务调用花费的时间比我们预期的要长得多。我们做了一些调查并放置了一些计时器,我们将其缩小到创建我们的 Entity Framework 6 DbContext 的实例。不是查询本身,只是上下文的创建。从那以后,我进行了一些日志记录,以查看创建 DbContext 的实例实际实际花费的平均时间,似乎大约是 50 毫秒。
应用程序预热后,上下文创建速度并不慢。应用程序回收后,它从 2-4 毫秒开始(这是我们在开发环境中看到的)。随着时间的推移,上下文创建似乎变慢了。在接下来的几个小时内,它将爬升到 50-80 毫秒的范围并趋于平稳。
我们的上下文是一个相当大的代码优先上下文,包含大约 300 个实体 - 包括一些实体之间的一些非常复杂的关系。我们正在运行 EF 6.1.3。我们正在执行“每个请求一个上下文”,但对于我们的大多数 Web API 调用,它只执行一个或两个查询。创建上下文需要 60+ms,然后执行 1ms 查询有点不满意。我们每分钟大约有 10k 个请求,因此我们不是一个经常使用的网站。
这是我们所看到的快照。时代在 MS 中,大跌是回收应用程序域的部署。每行是 4 个不同的 Web 服务器之一。请注意,它也不总是同一台服务器。
我确实进行了内存转储以尝试充实正在发生的事情,这是堆统计信息:
00007ffadddd1d60 70821 2266272 System.Reflection.Emit.GenericFieldInfo
00007ffae02e88a8 29885 2390800 System.Linq.Enumerable+WhereSelectListIterator`2[[NewRelic.Agent.Core.WireModels.MetricDataWireModel, NewRelic.Agent.Core],[System.Single, mscorlib]]
00007ffadda7c1a0 1462 2654992 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.Object, mscorlib],[System.Object, mscorlib]][]
00007ffadd4eccf8 83298 2715168 System.RuntimeType[]
00007ffadd4e37c8 24667 2762704 System.Reflection.Emit.DynamicMethod
00007ffadd573180 30013 3121352 System.Web.Caching.CacheEntry
00007ffadd2dc5b8 35089 3348512 System.String[]
00007ffadd6734b8 35233 3382368 System.RuntimeMethodInfoStub
00007ffadddbf0a0 24667 3749384 System.Reflection.Emit.DynamicILGenerator
00007ffae04491d8 67611 4327104 System.Data.Entity.Core.Metadata.Edm.MetadataProperty
00007ffadd4edaf0 57264 4581120 System.Signature
00007ffadd4dfa18 204161 4899864 System.RuntimeMethodHandle
00007ffadd4ee2c0 41900 5028000 System.Reflection.RuntimeParameterInfo
00007ffae0c9e990 21560 5346880 System.Data.SqlClient._SqlMetaData
00007ffae0442398 79504 5724288 System.Data.Entity.Core.Metadata.Edm.TypeUsage
00007ffadd432898 88807 8685476 System.Int32[]
00007ffadd433868 9985 9560880 System.Collections.Hashtable+bucket[]
00007ffadd4e3160 92105 10315760 System.Reflection.RuntimeMethodInfo
00007ffadd266668 493622 11846928 System.Object
00007ffadd2dc770 33965 16336068 System.Char[]
00007ffadd26bff8 121618 17335832 System.Object[]
00007ffadd2df8c0 168529 68677312 System.Byte[]
00007ffadd2d4d08 581057 127721734 System.String
0000019cf59e37d0 166894 143731666 Free
Total 5529765 objects
Fragmented blocks larger than 0.5 MB:
Addr Size Followed by
0000019ef63f2140 2.9MB 0000019ef66cfb40 Free
0000019f36614dc8 2.8MB 0000019f368d6670 System.Data.Entity.Core.Query.InternalTrees.SimpleColumnMap[]
0000019f764817f8 0.8MB 0000019f76550768 Free
0000019fb63a9ca8 0.6MB 0000019fb644eb38 System.Data.Entity.Core.Common.Utils.Set`1[[System.Data.Entity.Core.Metadata.Edm.EntitySet, EntityFramework]]
000001a0f6449328 0.7MB 000001a0f64f9b48 System.String
000001a0f65e35e8 0.5MB 000001a0f666e2a0 System.Collections.Hashtable+bucket[]
000001a1764e8ae0 0.7MB 000001a17659d050 System.RuntimeMethodHandle
000001a3b6430fd8 0.8MB 000001a3b6501aa0 Free
000001a4f62c05c8 0.7MB 000001a4f636e8a8 Free
000001a6762e2300 0.6MB 000001a676372c38 System.String
000001a7761b5650 0.6MB 000001a776259598 System.String
000001a8763c4bc0 2.3MB 000001a8766083a8 System.String
000001a876686f48 1.4MB 000001a8767f9178 System.String
000001a9f62adc90 0.7MB 000001a9f63653c0 System.String
000001aa362b8220 0.6MB 000001aa36358798 Free
这似乎是相当多的元数据和类型用法。
我们尝试过的事情:
我们可以进一步调查什么?我知道 EF 使用的缓存很大,可以加快速度。缓存中有更多东西会减慢上下文创建速度吗?有没有一种方法可以准确地查看该缓存中的内容以充实其中的任何奇怪内容?有谁知道我们具体可以做什么来加速上下文创建?
更新 - 2017 年 5 月 30 日
我获取了 EF6 源代码并编译了我们自己的版本以坚持一些时间。我们经营着一个非常受欢迎的网站,因此收集大量时间信息很棘手,我没有达到我想要的程度,但基本上我们发现所有减速都来自 this method
public void ForceOSpaceLoadingForKnownEntityTypes()
{
if (!_oSpaceLoadingForced)
{
// Attempting to get o-space data for types that are not mapped is expensive so
// only try to do it once.
_oSpaceLoadingForced = true;
Initialize();
foreach (var set in _genericSets.Values.Union(_nonGenericSets.Values))
{
set.InternalSet.TryInitialize();
}
}
}
foreach 的每次迭代都会命中我们上下文中 DBSet 定义的每个实体。每次迭代都相对较短 0.1-0.3 毫秒,但是当您添加我们拥有的 254 个实体时,它会加起来。我们仍然没有弄清楚为什么它一开始很快就变慢了。
最佳答案
这里是我开始解决问题的地方,而不是转向对企业更友好的解决方案。
Our context is a fairly large code-first context with around 300 entities
虽然 EF 随着时间的推移有了很大的改进,但我仍然会开始认真考虑在你达到 100 个实体后切碎东西(实际上我会早于此开始,但这似乎是许多人所说的神奇数字 - 共识?)。将其视为为“上下文”设计,但使用“域”一词代替?这样你就可以向你的高管推销你正在应用“领域驱动设计”来修复应用程序?也许您正在为 future 的“微服务”进行设计,然后您在一个段落中使用了两个流行语。 ;-)
我不是企业领域 EF 的忠实粉丝,因此我倾向于避免在大规模或高性能应用程序中使用它。你的旅费可能会改变。对于 SMB,它可能完全没问题。不过,我确实遇到过使用它的客户。
我不确定以下想法是否完全最新,但根据经验,我会考虑其他一些事情。
看起来您已经在应用程序上运行某种类型的探查器,所以我假设您还查看了 SQL 查询和可能的性能提升。是的,我知道这不是您要解决的问题,但从用户的角度来看,它可以促成整个问题。
针对@WiktorZichia 关于未回答有关性能问题的评论,在企业系统中消除此类问题的最佳方法是消除 Entity Framework 。每个决定都需要权衡取舍。 EF 是一个很好的抽象,可以加快开发速度。但它会带来一些不必要的开销,可能会大规模损害系统。现在,从技术上讲,我仍然没有回答“我如何按照我试图解决的方式解决这个问题”的问题,所以这可能仍然被视为失败。
关于c# - 创建 Entity Framework Context 的实例在负载下变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43523374/
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法