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) > > > > > { > > > > > RunComparisons(CreateComparerLCG); > > > > > RunComparisons(CreateComparerTypeConverter); > > > > > } > > > > > > > //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 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 6, 9:23 am, webpaul <[email protected]> wrote: > > > > > > This does it in 93ms vs. 6500ms on my box, could be improved with > a > > > > > > Dictionary as well. Also, it always converts to the first type so > if > > > > > > you compare byte.MaxValue with int.MaxValue you get an exception. > It > > > > > > should convert to the largest type so I'll see what I can do on > that > > > > > > as well. > > > > > > > > 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(firstType); > > > > > > > > return delegate(object first, object second) > > > > > > { > > > > > > return > > > > > > object.Equals( > > > > > > converterFirstType.ConvertTo(first, > > > > > > firstType), > > > > > > converterFirstType.ConvertTo( > > > > > > converterSecondType.ConvertTo(second, > > > > > > secondType), > > > > > > firstType > > > > > > ) > > > > > > ) > > > > > > ; > > > > > > }; > > > > > > } > > > > > > > > On Mar 6, 9:10 am, webpaul <[email protected]> wrote: > > > > > > > > > It's pretty slow as is - takes 6.5 seconds for 10K iterations. > I'm > > > > > > > going to try it a few different ways and see which is fastest. > > > > > > > > > class Program > > > > > > > { > > > > > > > static void Main(string[] args) > > > > > > > { > > > > > > > RunComparisons(CreateComparerLCG); > > > > > > > } > > > > > > > > > //Comparison types > > > > > > > > > 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 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 }, > > > > > > > }; > > > > > > > > > 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)) > > > > > > > throw new > ApplicationException("Comparison > > > > > > > didn't work"); > > > > > > > } > > > > > > > }; > > > > > > > watch.Stop(); > > > > > > > Console.WriteLine("All comparisons took " + > > > > > > > watch.ElapsedMilliseconds + "ms"); > > > > > > > } > > > > > > > > > private class Comparison > > > > > > > { > > > > > > > public object item; > > > > ... > > > > 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 -~----------~----~----~----~------~----~------~--~---
