use ConcurrentDictionary to replace lock in expression cache #51
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
PR Description
Hello, thank you very much for your work! It has been very helpful for my project. In this PR, I suggest replacing the expression cache's
Dictionary
(with lock) withConcurrentDictionary
.While the performance impact of a lock is usually acceptable, when
Eval()
is heavily used to evaluate the same expressions (which is precisely when and why we need caching), it puts more pressure on threads and the CPU, making it more time-consuming compared to theConcurrentDictionary
.ConcurrentDictionary
has been heavily optimized for multi-thread scenarios, especially when there are many reads and fewer writes. Its read performance is almost identical to aDictionary
without any lock.Considering that this library targets net45, netstandard1.3, and netstandard2.0, all of which support
ConcurrentDictionary
, this change should be feasible. If, for some reason, there is a need to support older versions in the future, we can use #if and #elif compilation directives.Additionally, I have updated the README. When my colleagues and I first used this library last year and this year, we made the same mistake, instantiated a new instance each time we called it instead of making it a singleton. This wasted its caching capabilities. Also, if a user frequently evaluates many unique expressions, it might put pressure on memory in default. Therefore, I believe it is necessary to include this parameter in the README to help new users utilize this excellent work more effectively.