2

我正在使用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:CompileAssemblyFromDom()将少量程序集(<200)保存到磁盘时该方法的性能比加载到内存要差,但是当数量增加(~500-1000)时,性能会差几个数量级?是什么导致了这种奇怪的行为?

4

1 回答 1

0

我找到了这个链接,作者 Rick Strahl 说 CodeDomProvider 编译器在应用程序域中加载编译的程序集:

应用程序域加载程序集,但不能卸载它们!

这也是 MSDN 所说的:看这个

所以问题是程序集都驻留在内存中,从而减慢了系统速度。

于 2015-07-01T11:01:15.083 回答