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)
> >                    {
> >                        return object.Equals(
> >                            second,
> >                            converterSecondType.ConvertTo(first,
> > secondType)
> >                        );
> >                    }
> >                };
>
> >                 comparerCacheClass.Add(key, compareExpression);
> >            }
>
> >            return compareExpression;
> >         }
>
> >        private static void RunComparisons(Func<Type, Type,
> > Func<object, object, bool>> createComparer)
> >        {
> >            List<Comparison> comparisonsToMake = new List<Comparison>
> > {
> >                new Comparison { item = (byte)1, otherItem = (int)1 },
> >                new Comparison { item = (int)1, otherItem = (long)1 },
> >                new Comparison { item = (long)1, otherItem = (float)
> > 1 },
> >                new Comparison { item = (float)1, otherItem = (double)
> > 1 },
> >                new Comparison { item = (byte)byte.MaxValue, otherItem
> > = (int)int.MaxValue, expectedValue = false },
> >            };
>
> >            Program program = new Program();
>
> >            Stopwatch watch = new Stopwatch();
> >            watch.Start();
> >            for (int i = 0; i < 10000; i++)
> >            {
> >                foreach (var comparison in comparisonsToMake)
> >                {
> >                    if (program.Compare(comparison, createComparer) !=
> > comparison.expectedValue)
> >                        throw new ApplicationException("Comparison
> > didn't work");
> >                }
> >            };
> >            watch.Stop();
> >            Console.WriteLine("All comparisons took " +
> > watch.ElapsedMilliseconds + "ms");
> >        }
>
> >        private class Comparison
> >        {
> >            public object item;
> >            public object otherItem;
> >            public bool expectedValue = true;
> >        }
>
> >        private bool Compare(Comparison comparison, Func<Type, Type,
> > Func<object, object, bool>> createComparer)
> >        {
> >            object item = comparison.item;
> >            object otherItem = comparison.otherItem;
>
> >            if (item == null | otherItem == null)
> >                return item == null & otherItem == null;
>
> >            var equalityComparer = createComparer(item.GetType(),
> > otherItem.GetType());
>
> >            return equalityComparer(item, otherItem);
> >        }
>
> >    }
>
> > On Mar 7, 8:36 am, Simone Busoli <[email protected]> wrote:
> > > Sorry Paul, I'm not going to reply anymore. Write a test, write a patch
> > and
> > > submit it if you think that using type converters is a better option.
>
> > > On Sat, Mar 7, 2009 at 15:32, webpaul <[email protected]> wrote:
>
> > > > Type converter is still faster than dictionary cached LCG (without
> > > > overflow problem solved) and I'm not even caching the type converter
> > > > yet... The LCG solution does handle the overflow condition gracefully
> > > > and I don't fully understand how it isn't overflowing, can you explain
> > > > how what you are doing doesn't fail when converting int.MaxValue to a
> > > > byte?
>
> > > > Also, how do you guys handle multi-key dictionaries typically? I have
> > > > a way but am curious how you usually do it.
>
> > > > On Mar 6, 10:02 am, Simone Busoli <[email protected]> wrote:
> > > > > Try caching the LCG comparer, you'll be surprised.
>
> > > > > On Fri, Mar 6, 2009 at 16:46, webpaul <[email protected]> wrote:
>
> > > > > > This one takes 1000ms vs 6500ms but it handles one of the types
> > being
> > > > > > an overflow for the other. I couldn't find a way to detect if there
> > > > > > will be an overflow for a specific value without actually catching
> > the
> > > > > > overflow exception which makes this take much longer. Any ideas?
>
> > > > > >    class Program
> > > > > >    {
> > > > > >        static void Main(string[] args)
>
> ...
>
> 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
-~----------~----~----~----~------~----~------~--~---

Reply via email to