Skip to content

Commit 786522e

Browse files
WAcryVitaliyMF
authored andcommitted
use concurrent dictionary to replace lock
1 parent 9788cc7 commit 786522e

File tree

2 files changed

+18
-10
lines changed

2 files changed

+18
-10
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ By default `LambdaParser` uses `ValueComparer` for values comparison. You can pr
3838
var valComparer = new ValueComparer() { NullComparison = ValueComparer.NullComparisonMode.Sql };
3939
var lambdaParser = new LambdaParser(valComparer);
4040
```
41+
### Caching Expressions
42+
43+
The `UseCache` property determines whether the `LambdaParser` should cache parsed expressions. By default, `UseCache` is set to `true`, meaning expressions are cached to improve performance for repeated evaluations of the same expression.
44+
45+
Therefore, using a singleton instance of `LambdaParser` is recommended, rather than creating a new instance each time.
46+
47+
You can disable caching by setting UseCache to false if you want to save memory, especially when evaluating a large number of unique expressions.
48+
49+
```csharp
50+
var lambdaParser = new LambdaParser();
51+
lambdaParser.UseCache = false;
52+
```
4153

4254
## Who is using this?
4355
NReco.LambdaParser is in production use at [SeekTable.com](https://www.seektable.com/) and [PivotData microservice](https://www.nrecosite.com/pivotdata_service.aspx) (used for user-defined calculated cube members: formulas, custom formatting).

src/NReco.LambdaParser/Linq/LambdaParser.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#endregion
1414

1515
using System;
16+
using System.Collections.Concurrent;
1617
using System.Collections.Generic;
1718
using System.Linq;
1819
using System.Linq.Expressions;
@@ -36,9 +37,8 @@ public class LambdaParser {
3637
static readonly string[] mulOps = new[] {"*", "/", "%" };
3738
static readonly string[] addOps = new[] { "+", "-" };
3839
static readonly string[] eqOps = new[] { "==", "!=", "<", ">", "<=", ">=" };
39-
40-
readonly IDictionary<string, CompiledExpression> CachedExpressions = new Dictionary<string, CompiledExpression>();
41-
readonly object _lock = new object();
40+
41+
readonly IDictionary<string, CompiledExpression> CachedExpressions = new ConcurrentDictionary<string, CompiledExpression>();
4242

4343
/// <summary>
4444
/// Gets or sets whether LambdaParser should use the cache for parsed expressions.
@@ -124,9 +124,7 @@ public object Eval(string expr, IDictionary<string, object> vars) {
124124
public object Eval(string expr, Func<string,object> getVarValue) {
125125
CompiledExpression compiledExpr = null;
126126
if (UseCache) {
127-
lock (_lock) {
128-
CachedExpressions.TryGetValue(expr, out compiledExpr);
129-
}
127+
CachedExpressions.TryGetValue(expr, out compiledExpr);
130128
}
131129

132130
if (compiledExpr == null) {
@@ -136,11 +134,9 @@ public object Eval(string expr, Func<string,object> getVarValue) {
136134
};
137135
var lambdaExpr = Expression.Lambda(linqExpr, compiledExpr.Parameters);
138136
compiledExpr.Lambda = lambdaExpr.Compile();
139-
137+
140138
if (UseCache)
141-
lock (_lock) {
142-
CachedExpressions[expr] = compiledExpr;
143-
}
139+
CachedExpressions[expr] = compiledExpr;
144140
}
145141

146142
var valuesList = new List<object>();

0 commit comments

Comments
 (0)