-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve performance by compiling into lambda method calls, property getters etc #4
Comments
Hi, i was just going to add an issue for that, but what you described is quite close assuming I have IQueryable interface, i'd like to build filtering predicate expression for the where function: Expression<Func<T, bool>> ** edit
possible? Thanks |
yes - this is possible. In fact you already can do that with some piece of extra code smth like:
Also you can check how I guess it is possible to add overloads like BTW, this issue is about quote another thing - evaluation performance optimization. Linq expressions itself are strongly typed, but in most cases this is badly usable for user-defined formulas or expressions, especially if variables are not strongly typed. LambdaParser supports evaluation that is similar to C# 'dynamic' type (thats why internally LambdaParameterWrapper is used) but this has some implication on execution performance - it starts to be noticeable when expression is evaluated > 100,000 times (say, for dataset filtering). It is still a place to get better execution time by replacing reflection methods invocation with cache of delegates. |
So, I am using this for some configurable formula evaluations. I can always make a class that inherits from LambdaParser but it would be nice if this was already included. I want two things out of this; 1) To have a cached compiled delegate returned and 2) to have a dictionary of Func (value getters) so values could be dynamically retrieved upon invocation. I might have gotten confused about the reason for this issue but here is a sample idea of how this could be done. A cached of value getter results may be useful too if something is static but that would take some thought as it kind of conflicts with this. This is also not very useful if caching is turned off. public Func<object> CreateDelegate(string expr, IDictionary<string, Func<object>> valueGetters)
{
return () => Eval(expr, valueGetters);
}
public object Eval(string expr, IDictionary<string, Func<object>> vars) {
return Eval(expr, (varName) => {
Func<object> val = null;
vars.TryGetValue(varName, out val);
return val?.Invoke();
});
} |
@some1one this issue is actually about reflection-based invocations made with InvokeMethod.cs: they may be even faster when compiled to delegate, this is possible in some cases (when no method overloads for the same number of arguments). As I understand, you mean caching of variables; I've no idea why you need one more "Eval" overload as you can easily cache variables on your side with
No need to inherit from LambdaParser; if you like you can add extension method that adds this 'variables caching' behavior and use it in your project. However, caching of variables may cause various side-effects and usually this is very project-specific thing. For now I'm not sure that it is better to include this code into library. |
Okay, I understand now. I don't need that kind of performance for this project, but the custom filtering use case has already come up on another project that I am considering this for now. I'll have to do some benchmark s to see if will actually be a problem though. And for the variable caching, yes, that makes a lot more sense when I think about it that way. |
Right now all invocations are performed through reflection (InvokeMethod / InvokeDelegate / InvokeIndexer / InvokePropertyOrField). At the same time, evaluation performance is acceptable for most applications: 10,000 evals take about 20-30ms (depending on CPU).
It is possible to improve evaluation performance in cases if invocation is not ambiguous (only one method overload is available according to number of parameters); this might be useful if LambdaParser is used for in-memory filtering of large dataset (say, >100k rows) by user-defined expression.
If someone needs this improvement please leave a comment or vote for this issue.
The text was updated successfully, but these errors were encountered: