From 8559845fcfc60add8fffcff8a7da73162d2381b6 Mon Sep 17 00:00:00 2001 From: Aron Tsang Date: Thu, 12 Dec 2013 10:39:25 +0800 Subject: [PATCH] Change to use a Linq expression for constructing the FieldCrawler, since Reflection is slower than Linq and is hundreds of times slower when you cache the Linq compiled code. Since we tight loop over the constructor for each field we read, that is a HUGE amount of time spent in the reflection library. --- .../ExtendedFieldCrawlerFactory.cs | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/scSearchContrib.Crawler/FieldCrawlers/ExtendedFieldCrawlerFactory.cs b/scSearchContrib.Crawler/FieldCrawlers/ExtendedFieldCrawlerFactory.cs index f02d4d5..6914e60 100644 --- a/scSearchContrib.Crawler/FieldCrawlers/ExtendedFieldCrawlerFactory.cs +++ b/scSearchContrib.Crawler/FieldCrawlers/ExtendedFieldCrawlerFactory.cs @@ -1,5 +1,6 @@ namespace scSearchContrib.Crawler.FieldCrawlers { + using System; using System.Collections.Generic; using Sitecore.Collections; @@ -36,7 +37,7 @@ public static IEnumerable GetFieldCrawlerValues(Field field, SafeDiction if (!string.IsNullOrEmpty(fieldCrawlerType)) { - var fieldCrawler = ReflectionUtil.CreateObject(fieldCrawlerType, new object[] { field }); + var fieldCrawler = GetFieldCrawlerByType(fieldCrawlerType, field); if (fieldCrawler is IMultivaluedFieldCrawler) { @@ -52,5 +53,44 @@ public static IEnumerable GetFieldCrawlerValues(Field field, SafeDiction return new[] { new DefaultFieldCrawler(field).GetValue() }; } + + private static object GetFieldCrawlerByType(string fieldCrawlerType, Field field) + { + Func constructor; + // We could put in interlocks into the below code. However it is idempotent. + // Yes it will be non-optimal if multiple threads access the same type at the same time + // However afterwards, we will have better perf, when there is no locking. + // Plus its simplier :) + if (_compiledExpressions.TryGetValue(fieldCrawlerType, out constructor) == false) + { + _compiledExpressions[fieldCrawlerType] = constructor = ConstructorExpression(fieldCrawlerType); + } + return constructor(field); + } + + // Cache the IL for constructing FieldCrawlers + // Expression compile is expensive. But still SOOO much cheaper than reflection that it is replacing. + private readonly static Dictionary> _compiledExpressions = new Dictionary>(); + + + // Create IL to run the constructor. + private static Func ConstructorExpression(string typeName) + { + var type = Type.GetType(typeName); + if (type == null) + return field => null; + + var constructor = type.GetConstructor(new[] {typeof (Field)}); + + if (constructor == null) + return field => null; + + var paramExpression = System.Linq.Expressions.Expression.Parameter(typeof (Field), "field"); + var newExpression = System.Linq.Expressions.Expression.New(constructor, paramExpression); + var lambda = System.Linq.Expressions.Expression.Lambda>(newExpression, paramExpression); + + return lambda.Compile(); + + } } }