You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The initial use cases for these types was for long-lived processes, where overall it's a better use of resources to spend more time at construction time to optimize the data structures and algorithms used for later data access. However, the current construction time is one or more orders of magnitude more than for the standard dictionary/set types. We need to a) invest in driving down those construction costs, and b) consider making the default performance of ToFrozenDictionary/Set as close that of Dictionary/Set as possible via an additional optional parameter to these methods, e.g.
public static FrozenSet<T> ToFrozenSet<T>(this IEnumerable<T> source, IEqualityComparer<T>? comparer = null,
+ double constructionOptimization = default // pick a better name
);
When 0.0, this would effectively default to creating a FrozenSet/Dictionary that just wrapped a HashSet/Dictionary, providing the same FrozenSet/Dictionary semantics but primarily just as a wrapper for a HashSet/Dictionary, such that the only additional costs were cloning of the data (assuming the Items/Keys/Values properties remain as they are today, they could be lazily-created on first need). On a scale from 0.0 to 1.0, the larger the double value, the more optimization would be performed at construction time, enabling the caller to choose how much time is spent at construction vs how fast subsequent data access can be made, with 1.0 meaning construction would take the longest in exchange for fastest data access. Having the default be fast construction would make this the least surprising for casual use and would avoid falling into pits of failure in the average case; consumers willing to spend more time at construction because they know their processes will be long-lived can then opt-in to longer startup times.
Creating frozen dictionaries (and sets) optimized for reading where keys are strings or integers is now from 39% to 94% (16 times!) faster. In all cases except of one, it's few times faster than the creation of immutable dictionary.
AFAIR, we've more recently rejected using double in places like this due to a lot of nuance in what exactly the values mean. There are also always concerns around the imprecision/rounding error introduced by converting user-specified decimal-based literals to a binary-based representation, potential edge cases when used in certain arithmetic operations, etc.
Using an integer from 0-100 would be significantly clearer. Having some other value or type to represent the information may likewise be better itself.
-- Half of all representable positive doubles are between [0, 1]. Of those roughly 2^62 values, we get 2^52 evenly distributed values. float is similar, but with 8 million (2^23) evenly distributed values out of roughly 1 billion (2^30) that exist between [0, 1].
Adam copied this text out of an old issue. It's stale. We long ago decided to add this instead as a bool optimizeForReading, which we did in a previous preview release, and with all the improvements Adam has made, I intend to remove those overloads and not differentiate.
Reacted by Tanner Gooding, Marc Brooks and Joe4evr
Activity
[-]Construction performance[/-][+]Frozen collection construction performance[/+]adamsitnik commentedon Jun 23, 2023
I've written a lot of new benchmarks to cover the most important strategies: dotnet/performance#3089
And send five PRs that improve the creation time:
#87510 (already merged)
#87630 (already merged)
#87688 (already merged)
#87876 (already merged)
#87960 (already merged)
Creating frozen dictionaries (and sets) optimized for reading where keys are strings or integers is now from 39% to 94% (16 times!) faster. In all cases except of one, it's few times faster than the creation of immutable dictionary.
Details
10 strings
100 strings
1000 strings
10000 strings
danmoseley commentedon Jun 23, 2023
Cc @geeknoid
tannergooding commentedon Jun 23, 2023
AFAIR, we've more recently rejected using
doublein places like this due to a lot of nuance in what exactly the values mean. There are also always concerns around the imprecision/rounding error introduced by converting user-specified decimal-based literals to a binary-based representation, potential edge cases when used in certain arithmetic operations, etc.Using an integer from 0-100 would be significantly clearer. Having some other value or type to represent the information may likewise be better itself.
-- Half of all representable positive doubles are between
[0, 1]. Of those roughly 2^62 values, we get 2^52 evenly distributed values.floatis similar, but with 8 million (2^23) evenly distributed values out of roughly 1 billion (2^30) that exist between[0, 1].stephentoub commentedon Jun 23, 2023
Adam copied this text out of an old issue. It's stale. We long ago decided to add this instead as a bool optimizeForReading, which we did in a previous preview release, and with all the improvements Adam has made, I intend to remove those overloads and not differentiate.