我使用RazorEngine来解析应用中的html模板,并编写了一些NUnit测试来分析性能区域并调查潜在问题。似乎在指定GenerateInMemory = false
时,我的代码遭受了巨大的性能损失。
在NUnit中运行每个测试时,在CompileAssemblyFromDom()方法中花费的总滴答如下:
GenerateInMemory = false: 354,493,052 ticks
GenerateInMemory = true: 6,669,711,153 ticks
这比我预期的某些磁盘IO的额外成本更具极端影响。此外,这个时间似乎与测试的大小不成线性关系。例如,当我运行测试200次迭代而不是1000次(在内存中= false)时,结果是118M滴答,归一化到1000次测试迭代是591M滴答。这比相应的测试加载到内存中略大,但是当全尺寸测试最终完成时仍然比实际性能小一个数量级(我认为它是挂起的,但在写这个问题时完成)。
在保存大量动态程序集时,是否有任何理由对性能产生巨大影响?
测试代码:
for (int i = 0; i < 1000; i++)
{
string s = "<div>" + i + " some random text blah blah... no code specified</div>";
parser.GetHtmlFromTemplate(s, i.ToString());
}
/*
* Result:
* _codeDomProvider.CompileAssemblyFromDom: 354493052 ticks
*/
/* ... collect timing stats */
GetHtmlFromTemplate()代码:
public string GetHtmlFromTemplate(string template, string templateCacheName)
{
if (template == string.Empty) return string.Empty;
ITemplate templateInstance = templateService.GetTemplate(template, null, templateCacheName);
return templateInstance.Run(new ExecuteContext());
}
这里发生了一堆不相关的代码,最终我们到达了问题区域,这是CodeDomProvider用于编译代码的地方:
var compileTimer = new Stopwatch();
compileTimer.Start();
var compileUnit = GetCodeCompileUnit(context.ClassName, context.TemplateContent, context.Namespaces,
context.TemplateType, context.ModelType);
compileTimer.Stop();
var @params = new CompilerParameters
{
GenerateInMemory = InMemory, //in memory is a property of this object, and is set accordingly for each test
GenerateExecutable = false,
IncludeDebugInformation = false,
CompilerOptions = "/target:library /optimize"
};
//{...} do some reflection to get the referenced assemblies
var compileFromDomTimer = new Stopwatch();
compileFromDomTimer.Start();
var tuple = Tuple.Create(_codeDomProvider.CompileAssemblyFromDom(@params, compileUnit), someString);
compileFromDomTimer.Stop();
TLDR:将少量程序集(&lt; 200)保存到磁盘时CompileAssemblyFromDom()
方法的性能比加载到内存要差,但是当数量增加时(〜{}} 500-1000),性能是几个数量级更差?是什么导致了这种奇怪的行为?