Even the uncached type converter is faster than cached LCG, 11 seconds
instead of 13. Perhaps the LINQ expression implementation for
conversion is more expensive than the standard type converter.
private static Func<object, object, bool>
CreateComparerTypeConverter(Type firstType, Type secondType)
{
if (firstType == secondType)
return Equals;
TypeConverter converterFirstType =
TypeDescriptor.GetConverter(firstType);
TypeConverter converterSecondType =
TypeDescriptor.GetConverter(secondType);
int firstTypeSize =
System.Runtime.InteropServices.Marshal.SizeOf(firstType);
int secondTypeSize =
System.Runtime.InteropServices.Marshal.SizeOf(secondType);
if (secondTypeSize >= firstTypeSize)
{
return delegate(object first, object second)
{
return object.Equals(
second,
converterSecondType.ConvertTo(first,
secondType)
);
};
}
else
{
return delegate(object first, object second)
{
return object.Equals(
first,
converterFirstType.ConvertTo(second,
firstType)
);
};
}
}
On Mar 8, 7:15 pm, webpaul <[email protected]> wrote:
> Found a way to compare the type sizes. Using this method for previous
> examples, it returns in 37ms which would seem to be faster than the
> LCG. I wanted to rule out a larger startup time for LCG as opposed to
> execution time, so for 1 million rows the cached LCG takes 13 seconds
> and the type converter method below takes 3 seconds.
>
> Separate caches of course. :)
>
> private static Func<object, object, bool>
> CreateComparerTypeConverterCached(Type firstType, Type secondType)
> {
> if (firstType == secondType)
> return Equals;
>
> Func<object, object, bool> compareExpression = null;
> CacheKey key = new CacheKey { FirstType = firstType,
> SecondType = secondType };
> if (!comparerCacheClass.TryGetValue(key, out
> compareExpression))
> {
> TypeConverter converterFirstType =
> TypeDescriptor.GetConverter(firstType);
> TypeConverter converterSecondType =
> TypeDescriptor.GetConverter(secondType);
>
> int firstTypeSize =
> System.Runtime.InteropServices.Marshal.SizeOf(firstType);
> int secondTypeSize =
> System.Runtime.InteropServices.Marshal.SizeOf(secondType);
>
> if (secondTypeSize >= firstTypeSize)
> {
> compareExpression = delegate(object first, object
> second)
> {
> return object.Equals(
> second,
> converterSecondType.ConvertTo(first,
> secondType)
> );
> };
>
> }
> else
> {
> compareExpression = delegate(object first, object
> second)
> {
> return object.Equals(
> first,
> converterFirstType.ConvertTo(second,
> firstType)
> );
> };
> }
>
> comparerCacheClass.Add(key, compareExpression);
> }
>
> return compareExpression;
> }
>
> On Mar 7, 12:34 pm, webpaul <[email protected]> wrote:
>
>
>
> > Doh! Nice catch.
>
> > Looks like it is really 800ms, the try/catch is a killer because it's
> > in the delegate so caching it doesn't give a big benefit. If there was
> > an unchecked type converter or some way to tell which type was bigger
> > so I could always cast to that then I suspect the type converter would
> > be better. But as-is (including the overflow scenario) the cached LCG
> > is the best.
>
> > On Mar 7, 10:29 am, Simone Busoli <[email protected]> wrote:
>
> > > Did you realize that you're using a shared cache, which is already filled
> > > with delegates when you run the fourth step?
>
> > > On Sat, Mar 7, 2009 at 16:45, webpaul <[email protected]> wrote:
>
> > > > Until I know how you want to handle multi key dictionaries in your
> > > > code base I'm not going to submit a patch. Below is how I did it with
> > > > a class I usually use for that, more details at:
> > > >http://www.codeproject.com/KB/recipes/ClassKey.aspx
>
> > > > If anyone is interested, the LINQ expressions used in the LCG have a
> > > > checked/unchecked version which is why it didn't have the overflow
> > > > issue. As far as I can tell type converters don't have that feature
> > > > and using an unchecked block doesn't stop it from throwing an
> > > > exception. When the type converters are cached they are better than
> > > > the cached LCG unless I'm doing something wrong here.
>
> > > > Performance from worst to best, with the original test rows plus one
> > > > more for overflow condition:
>
> > > > 10K iterations * 5 tests per iteration:
>
> > > > LCG compiled each time - 8043ms
> > > > TypeConverter with try/catch : 869ms
> > > > LCG cached: 143ms
> > > > TypeConverter without try/catch (exception on overflow): 82ms
> > > > Type converter with try/catch cached: 23ms
>
> > > > class Program
> > > > {
> > > > static void Main(string[] args)
> > > > {
> > > > RunComparisons(CreateComparerLCG);
> > > > RunComparisons(CreateComparerTypeConverter);
> > > > RunComparisons(CreateComparerLCGCachedClass);
> > > > RunComparisons(CreateComparerTypeConverterCached);
> > > > }
>
> > > > //Comparison types
>
> > > > private static Func<object, object, bool>
> > > > CreateComparerTypeConverter(Type firstType, Type secondType)
> > > > {
> > > > if (firstType == secondType)
> > > > return Equals;
>
> > > > TypeConverter converterFirstType =
> > > > TypeDescriptor.GetConverter(firstType);
> > > > TypeConverter converterSecondType =
> > > > TypeDescriptor.GetConverter(secondType);
>
> > > > return delegate(object first, object second)
> > > > {
> > > > try
> > > > {
> > > > return object.Equals(
> > > > first,
> > > > converterFirstType.ConvertTo(second,
> > > > firstType)
> > > > );
> > > > }
> > > > catch (OverflowException)
> > > > {
> > > > return object.Equals(
> > > > second,
> > > > converterSecondType.ConvertTo(first,
> > > > secondType)
> > > > );
> > > > }
> > > > };
> > > > }
>
> > > > private static Func<object, object, bool> CreateComparerLCG
> > > > (Type firstType, Type secondType)
> > > > {
> > > > if (firstType == secondType)
> > > > return Equals;
>
> > > > var firstParameter = Expression.Parameter(typeof(object),
> > > > "first");
> > > > var secondParameter = Expression.Parameter(typeof(object),
> > > > "second");
>
> > > > var equalExpression = Expression.Equal(Expression.Convert
> > > > (firstParameter, firstType),
> > > > Expression.Convert(Expression.Convert(secondParameter,
> > > > secondType), firstType));
>
> > > > return Expression.Lambda<Func<object, object, bool>>
> > > > (equalExpression, firstParameter, secondParameter).Compile();
> > > > }
>
> > > > private class CacheKey : ClassKey<CacheKey>
> > > > {
> > > > public Type FirstType = null;
> > > > public Type SecondType = null;
>
> > > > public override object[] GetKeyValues()
> > > > {
> > > > return new object[] { FirstType, SecondType };
> > > > }
> > > > }
>
> > > > private class ComparerCacheClass : Dictionary<CacheKey,
> > > > Func<object, object, bool>> { }
> > > > private static readonly ComparerCacheClass comparerCacheClass
> > > > = new ComparerCacheClass();
> > > > private static Func<object, object, bool>
> > > > CreateComparerLCGCachedClass(Type firstType, Type secondType)
> > > > {
> > > > if (firstType == secondType)
> > > > return Equals;
>
> > > > var firstParameter = Expression.Parameter(typeof(object),
> > > > "first");
> > > > var secondParameter = Expression.Parameter(typeof(object),
> > > > "second");
>
> > > > var equalExpression = Expression.Equal(Expression.Convert
> > > > (firstParameter, firstType),
> > > > Expression.Convert(Expression.Convert(secondParameter,
> > > > secondType), firstType));
>
> > > > Func<object, object, bool> compareExpression = null;
> > > > CacheKey key = new CacheKey { FirstType = firstType,
> > > > SecondType = secondType };
> > > > if (!comparerCacheClass.TryGetValue(key, out
> > > > compareExpression))
> > > > {
> > > > compareExpression = Expression.Lambda<Func<object,
> > > > object, bool>>(equalExpression, firstParameter,
> > > > secondParameter).Compile();
> > > > comparerCacheClass.Add(key, compareExpression);
> > > > }
>
> > > > return compareExpression;
> > > > }
>
> > > > private static Func<object, object, bool>
> > > > CreateComparerTypeConverterCached(Type firstType, Type secondType)
> > > > {
> > > > if (firstType == secondType)
> > > > return Equals;
>
> > > > Func<object, object, bool> compareExpression = null;
> > > > CacheKey key = new CacheKey { FirstType = firstType,
> > > > SecondType = secondType };
> > > > if (!comparerCacheClass.TryGetValue(key, out
> > > > compareExpression))
> > > > {
> > > > TypeConverter converterFirstType =
> > > > TypeDescriptor.GetConverter(firstType);
> > > > TypeConverter converterSecondType =
> > > > TypeDescriptor.GetConverter(secondType);
>
> > > > compareExpression = delegate(object first, object
> > > > second)
> > > > {
> > > > try
> > > > {
> > > > return object.Equals(
> > > > first,
> > > > converterFirstType.ConvertTo(second,
> > > > firstType)
> > > > );
> > > > }
> > > > catch (OverflowException)
> > > >
>
> ...
>
> read more »- Hide quoted text -
>
> - Show quoted text -
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Rhino Tools Dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/rhino-tools-dev?hl=en
-~----------~----~----~----~------~----~------~--~---