Skip to content

Commit 1d32c75

Browse files
authored
Use concurrent dictionary in NMM - 17.11 backport (#17571)
* Use concurrent dictionary in NameMultiMap for CE yield cache (#17565) * Fixes
1 parent b1b810f commit 1d32c75

File tree

3 files changed

+40
-26
lines changed

3 files changed

+40
-26
lines changed

src/Compiler/Checking/CheckDeclarations.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5540,7 +5540,7 @@ let emptyTcEnv g =
55405540
eCallerMemberName = None
55415541
eLambdaArgInfos = []
55425542
eIsControlFlow = false
5543-
eCachedImplicitYieldExpressions = HashMultiMap(HashIdentity.Structural) }
5543+
eCachedImplicitYieldExpressions = HashMultiMap(HashIdentity.Structural, useConcurrentDictionary = true) }
55445544

55455545
let CreateInitialTcEnv(g, amap, scopem, assemblyName, ccus) =
55465546
(emptyTcEnv g, ccus) ||> List.collectFold (fun env (ccu, autoOpens, internalsVisible) ->

src/Compiler/Utilities/HashMultiMap.fs

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,56 @@
33
namespace Internal.Utilities.Collections
44

55
open System.Collections.Generic
6+
open System.Collections.Concurrent
67

78
// Each entry in the HashMultiMap dictionary has at least one entry. Under normal usage each entry has _only_
89
// one entry. So use two hash tables: one for the main entries and one for the overflow.
910
[<Sealed>]
10-
type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<'Key>) =
11+
type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<'Key>, ?useConcurrentDictionary: bool) =
1112

12-
let firstEntries = Dictionary<_, _>(size, comparer)
13+
let comparer = comparer
1314

14-
let rest = Dictionary<_, _>(3, comparer)
15+
let firstEntries: IDictionary<_, _> =
16+
if defaultArg useConcurrentDictionary false then
17+
ConcurrentDictionary<_, _>(comparer)
18+
else
19+
Dictionary<_, _>(size, comparer)
1520

16-
new(comparer: IEqualityComparer<'Key>) = HashMultiMap<'Key, 'Value>(11, comparer)
21+
let rest: IDictionary<_, _> =
22+
if defaultArg useConcurrentDictionary false then
23+
ConcurrentDictionary<_, _>(comparer)
24+
else
25+
Dictionary<_, _>(3, comparer)
1726

18-
new(entries: seq<'Key * 'Value>, comparer: IEqualityComparer<'Key>) as x =
19-
new HashMultiMap<'Key, 'Value>(11, comparer)
20-
then entries |> Seq.iter (fun (k, v) -> x.Add(k, v))
27+
new(comparer: IEqualityComparer<'Key>, ?useConcurrentDictionary: bool) =
28+
HashMultiMap<'Key, 'Value>(11, comparer, defaultArg useConcurrentDictionary false)
2129

22-
member x.GetRest(k) =
30+
new(entries: seq<'Key * 'Value>, comparer: IEqualityComparer<'Key>, ?useConcurrentDictionary: bool) as this =
31+
HashMultiMap<'Key, 'Value>(11, comparer, defaultArg useConcurrentDictionary false)
32+
then entries |> Seq.iter (fun (k, v) -> this.Add(k, v))
33+
34+
member _.GetRest(k) =
2335
match rest.TryGetValue k with
2436
| true, res -> res
2537
| _ -> []
2638

27-
member x.Add(y, z) =
39+
member this.Add(y, z) =
2840
match firstEntries.TryGetValue y with
29-
| true, res -> rest[y] <- res :: x.GetRest(y)
41+
| true, res -> rest[y] <- res :: this.GetRest(y)
3042
| _ -> ()
3143

3244
firstEntries[y] <- z
3345

34-
member x.Clear() =
46+
member _.Clear() =
3547
firstEntries.Clear()
3648
rest.Clear()
3749

38-
member x.FirstEntries = firstEntries
50+
member _.FirstEntries = firstEntries
3951

40-
member x.Rest = rest
52+
member _.Rest = rest
4153

42-
member x.Copy() =
43-
let res = HashMultiMap<'Key, 'Value>(firstEntries.Count, firstEntries.Comparer)
54+
member _.Copy() =
55+
let res = HashMultiMap<'Key, 'Value>(firstEntries.Count, comparer)
4456

4557
for kvp in firstEntries do
4658
res.FirstEntries.Add(kvp.Key, kvp.Value)
@@ -86,11 +98,11 @@ type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<
8698
for z in rest do
8799
f kvp.Key z
88100

89-
member x.Contains(y) = firstEntries.ContainsKey(y)
101+
member _.Contains(y) = firstEntries.ContainsKey(y)
90102

91-
member x.ContainsKey(y) = firstEntries.ContainsKey(y)
103+
member _.ContainsKey(y) = firstEntries.ContainsKey(y)
92104

93-
member x.Remove(y) =
105+
member _.Remove(y) =
94106
match firstEntries.TryGetValue y with
95107
// NOTE: If not ok then nothing to remove - nop
96108
| true, _res ->
@@ -108,14 +120,14 @@ type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<
108120
| _ -> firstEntries.Remove(y) |> ignore
109121
| _ -> ()
110122

111-
member x.Replace(y, z) = firstEntries[y] <- z
123+
member _.Replace(y, z) = firstEntries[y] <- z
112124

113-
member x.TryFind(y) =
125+
member _.TryFind(y) =
114126
match firstEntries.TryGetValue y with
115127
| true, res -> Some res
116128
| _ -> None
117129

118-
member x.Count = firstEntries.Count
130+
member _.Count = firstEntries.Count
119131

120132
interface IEnumerable<KeyValuePair<'Key, 'Value>> with
121133

@@ -184,6 +196,6 @@ type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<
184196
member s.CopyTo(arr, arrIndex) =
185197
s |> Seq.iteri (fun j x -> arr[arrIndex + j] <- x)
186198

187-
member s.IsReadOnly = false
199+
member _.IsReadOnly = false
188200

189201
member s.Count = s.Count

src/Compiler/Utilities/HashMultiMap.fsi

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ open System.Collections.Generic
99
[<Sealed>]
1010
type internal HashMultiMap<'Key, 'Value> =
1111
/// Create a new empty mutable HashMultiMap with the given key hash/equality functions.
12-
new: comparer: IEqualityComparer<'Key> -> HashMultiMap<'Key, 'Value>
12+
new: comparer: IEqualityComparer<'Key> * ?useConcurrentDictionary: bool -> HashMultiMap<'Key, 'Value>
1313

1414
/// Create a new empty mutable HashMultiMap with an internal bucket array of the given approximate size
1515
/// and with the given key hash/equality functions.
16-
new: size: int * comparer: IEqualityComparer<'Key> -> HashMultiMap<'Key, 'Value>
16+
new: size: int * comparer: IEqualityComparer<'Key> * ?useConcurrentDictionary: bool -> HashMultiMap<'Key, 'Value>
1717

1818
/// Build a map that contains the bindings of the given IEnumerable.
19-
new: entries: seq<'Key * 'Value> * comparer: IEqualityComparer<'Key> -> HashMultiMap<'Key, 'Value>
19+
new:
20+
entries: seq<'Key * 'Value> * comparer: IEqualityComparer<'Key> * ?useConcurrentDictionary: bool ->
21+
HashMultiMap<'Key, 'Value>
2022

2123
/// Make a shallow copy of the collection.
2224
member Copy: unit -> HashMultiMap<'Key, 'Value>

0 commit comments

Comments
 (0)