if a and b are double, does anyone know if
((dynamic)a) + ((dynamic) b)
is faster or slower than
Func<double,double,double>((x,y) => x + y)(a, b)
And can you explain why?
if a and b are double, does anyone know if
((dynamic)a) + ((dynamic) b)
is faster or slower than
Func<double,double,double>((x,y) => x + y)(a, b)
And can you explain why?
The first version will always be slower. In very simple terms with this version everything that the compiler can do at compile time has now to be done at runtime, ie. checking the types of a and b, finding if they support the + operator and so on. It will cache a lot of this stuff, but still it is much more work than invoking a delegate.
In the second version all those checks can be done during compilation. The cost at runtime are only the creation and invocation of the delegate.
For example, consider those methods:
static T Add<T>(T a, T b)
{
return ((dynamic)a) + ((dynamic)b);
}
in contrast to
static T Add<T>(T a, T b, Func<T, T, T> adder)
{
return adder(a, b);
}
This is what the compiler generates from the first method:
private static T Add<T>(T a, T b)
{
if (Program.<Add>o__SiteContainer0<T>.<>p__Site1 == null)
{
Program.<Add>o__SiteContainer0<T>.<>p__Site1 = CallSite<Func<CallSite, object, T>>.Create(Binder.Convert(CSharpBinderFlags.None, typeof(T), typeof(Program)));
}
Func<CallSite, object, T> arg_98_0 = Program.<Add>o__SiteContainer0<T>.<>p__Site1.Target;
CallSite arg_98_1 = Program.<Add>o__SiteContainer0<T>.<>p__Site1;
if (Program.<Add>o__SiteContainer0<T>.<>p__Site2 == null)
{
Program.<Add>o__SiteContainer0<T>.<>p__Site2 = CallSite<Func<CallSite, object, object, object>>.Create(Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.Add, typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
return arg_98_0(arg_98_1, Program.<Add>o__SiteContainer0<T>.<>p__Site2.Target(Program.<Add>o__SiteContainer0<T>.<>p__Site2, a, b));
}
I've done some crude measurements and on my machine the first version is about 5 times slower than the second. I have to admit that I would have expected the difference to be larger.
Update: As for a prove why this is slower than a delegate: Given that the generated call site code also involves the invocation of a delegate (arg_98_0
), this piece of code (invocation of delegate + X) must necessarily be slower than using a delegate only.
dynamic will definitely be slower than the strongly typed func the first time it runs. And as to why, I will refer you to the definitive answer by Eric Lippert here on Stackoverflow.
As I understand it, the recurring penalty will be og boxing, copying and/or allocating these values on the heap.