Antaris / RazorEngine

Open source templating engine based on Microsoft's Razor parsing engine
http://antaris.github.io/RazorEngine
Other
2.13k stars 576 forks source link

Performance when using anonymous or dynamic types #317

Open Rohland opened 9 years ago

Rohland commented 9 years ago

Just want to double check this is expected.

Sample code from documentation:

string template = "<div>Hello @Model.Name</div>";
dynamic model = new ExpandoObject();
model.Name = "Matt";

string result = Engine.Razor.RunCompile(template, "key", null, (object)model);

On my machine this takes 566ms.

Let's change this code a bit to test parsing a larger template:

string template = "<div>Hello @Model.Name</div>";
for (int i = 0; i < 10; i++)
{
     template += template;
}
dynamic model = new ExpandoObject();
model.Name = "Matt";

string result = Engine.Razor.RunCompile(template, "key", null, (object)model);

On my machine this takes 28,099ms (28 seconds)!

Let's convert the above to use a POCO model:

string template = "<div>Hello @Model.Name</div>";
for (int i = 0; i < 10; i++)
{
     template += template;
}

var user = new User();
user.Name = "Matt";

string result = Engine.Razor.RunCompile(template, "key", user.GetType(), user);

This takes a more reasonable 1,114ms.

I guess there is a bit of a performance hit when using dynamic/anonymous types, however the hit in the case of large templates is significant. Is this expected?

matthid commented 8 years ago

Thanks for the benchmarks bringing this up to my attention.

The interesting case are the following calls and not the first one which has the compilation overhead (starting a new compiler process, loading the assembly and so forth). It is expected to be around a second or more. But the huge gap looks indeed suspicious... Is there a huge difference in subsequent calls (which should be fast) as well?

Rohland commented 8 years ago

@matthid - as far as I recall, subsequent calls are fine. It seems related to compilation.

I was tracking memory as well. It looks like large templates consume quite a bit of memory. Taking a similar approach to above, compiling 20 random templates of about 15kb each results in about 400mb of unreleased memory after compilation.

matthid commented 8 years ago

Compilation is not really under our control, did you try to use Roslyn (which might be faster)? See https://antaris.github.io/RazorEngine/Roslyn.html

Rohland commented 8 years ago

@matthid - thanks for the suggestion, however using Roslyn nets the same result. Took about 29 seconds for that large template.

Also seeing the memory issue with Roslyn.

It looks like large templates consume quite a bit of memory. Taking a similar approach to above, compiling 20 random templates of about 15kb each results in about 400mb of unreleased memory after compilation.

I haven't seen anyone post about memory issues, however can reproduce this with a vanilla console app using RazorEngine. We're having to restart Windows Services in production each night to free up memory used by RazorEngine. Any ideas?

xiaolu6t commented 8 years ago

It's too slowler than reflaction.