Skip to content

Commit 9ee8f9e

Browse files
Tweaks to ConcurrentList and benchmarking.
1 parent bce9716 commit 9ee8f9e

13 files changed

Lines changed: 242 additions & 130 deletions
Lines changed: 68 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,89 @@
11
using Open.Diagnostics;
22
using System;
33
using System.Collections.Generic;
4+
using System.Diagnostics;
45
using System.Linq;
56

67
namespace Open.Collections;
78

89
public class CollectionBenchmark<T> : BenchmarkBase<Func<ICollection<T>>>
910
{
10-
public CollectionBenchmark(uint size, uint repeat, Func<ICollection<T>> factory, Func<int, T> itemFactory) : base(size, repeat, factory) => _items = Enumerable.Range(0, (int)TestSize * 2).Select(itemFactory).ToArray();
11+
public CollectionBenchmark(uint size, uint repeat, Func<ICollection<T>> factory, Func<int, T> itemFactory) : base(size, repeat, factory) => _items = Enumerable.Range(0, (int)TestSize * 2).Select(itemFactory).ToArray();
1112

12-
protected readonly T[] _items;
13+
protected readonly T[] _items;
1314

14-
protected override IEnumerable<TimedResult> TestOnceInternal()
15-
{
15+
protected override IEnumerable<TimedResult> TestOnceInternal()
16+
{
1617
ICollection<T> c = Param();
1718

18-
yield return TimedResult.Measure("Fill (.Add(item))", () =>
19-
{
20-
for (int i = 0; i < TestSize; i++) c.Add(_items[i]);
21-
});
22-
23-
yield return TimedResult.Measure("Enumerate", () =>
24-
{
25-
// ReSharper disable once NotAccessedVariable
26-
int x = 0;
27-
// ReSharper disable once LoopCanBeConvertedToQuery
28-
foreach (T _ in c) { x++; }
29-
});
30-
31-
yield return TimedResult.Measure(".Contains(item)", () =>
32-
{
33-
for (int i = 0; i < TestSize; i++)
34-
{
19+
yield return TimedResult.Measure("Fill (.Add(item))", () =>
20+
{
21+
for (int i = 0; i < TestSize; i++) c.Add(_items[i]);
22+
});
23+
24+
yield return TimedResult.Measure("Enumerate (8 times)", () =>
25+
{
26+
for (int i = 0; i < 8; ++i)
27+
{
28+
// ReSharper disable once NotAccessedVariable
29+
int x = 0;
30+
// ReSharper disable once LoopCanBeConvertedToQuery
31+
foreach (T _ in c) { x++; }
32+
Debug.Assert(x == TestSize);
33+
}
34+
});
35+
36+
yield return TimedResult.Measure(".Contains(item)", () =>
37+
{
38+
for (int i = 0; i < TestSize; i++)
39+
{
3540
bool _ = c.Contains(_items[i]);
36-
}
37-
});
38-
39-
if (c is IList<T> list)
40-
{
41-
yield return TimedResult.Measure("IList<T> Read Access", () =>
42-
{
43-
for (int i = 0; i < TestSize; i += 2)
44-
{
45-
T _ = list[i];
46-
}
47-
});
48-
}
49-
50-
yield return TimedResult.Measure("Empty Backwards (.Remove(last))", () =>
51-
{
52-
for (int i = 0; i < TestSize; i++) c.Remove(_items[TestSize - i - 1]);
53-
});
54-
55-
yield return TimedResult.Measure("Refill (.Add(item))", () =>
56-
{
57-
for (int i = 0; i < TestSize; i++) c.Add(_items[i]);
58-
});
59-
60-
yield return TimedResult.Measure("Empty Forwards (.Remove(first))", () =>
61-
{
62-
for (int i = 0; i < TestSize; i++) c.Remove(_items[i]);
63-
});
64-
65-
for (int i = 0; i < TestSize; i++) c.Add(_items[i]);
66-
67-
yield return TimedResult.Measure(".Clear()", () => c.Clear());
68-
}
41+
}
42+
});
43+
44+
if (c is IList<T> list)
45+
{
46+
yield return TimedResult.Measure("IList<T> Read Access", () =>
47+
{
48+
for (int i = 0; i < TestSize; i += 2)
49+
{
50+
T _ = list[i];
51+
}
52+
});
53+
}
54+
55+
yield return TimedResult.Measure("Empty Backwards (.Remove(last))", () =>
56+
{
57+
for (int i = 0; i < TestSize; i++) c.Remove(_items[TestSize - i - 1]);
58+
});
59+
60+
yield return TimedResult.Measure("Refill (.Add(item))", () =>
61+
{
62+
for (int i = 0; i < TestSize; i++) c.Add(_items[i]);
63+
});
64+
65+
yield return TimedResult.Measure("Empty Forwards (.Remove(first))", () =>
66+
{
67+
for (int i = 0; i < TestSize; i++) c.Remove(_items[i]);
68+
});
69+
70+
for (int i = 0; i < TestSize; i++) c.Add(_items[i]);
71+
72+
yield return TimedResult.Measure(".Clear()", () => c.Clear());
73+
}
6974
}
7075

7176
public class CollectionBenchmark : CollectionBenchmark<object>
7277
{
73-
public CollectionBenchmark(uint size, uint repeat, Func<ICollection<object>> factory)
74-
: base(size, repeat, factory, _ => new object())
75-
{
76-
}
78+
public CollectionBenchmark(uint size, uint repeat, Func<ICollection<object>> factory)
79+
: base(size, repeat, factory, _ => new object())
80+
{
81+
}
7782

78-
public static TimedResult[] Results<T>(uint size, uint repeat, Func<ICollection<T>> factory, Func<int, T> itemFactory)
79-
=> new CollectionBenchmark<T>(size, repeat, factory, itemFactory).Result;
83+
public static TimedResult[] Results<T>(uint size, uint repeat, Func<ICollection<T>> factory, Func<int, T> itemFactory)
84+
=> new CollectionBenchmark<T>(size, repeat, factory, itemFactory).Result;
8085

81-
public static TimedResult[] Results<T>(uint size, uint repeat, Func<ICollection<T>> factory)
82-
where T : new()
83-
=> new CollectionBenchmark<T>(size, repeat, factory, _ => new T()).Result;
86+
public static TimedResult[] Results<T>(uint size, uint repeat, Func<ICollection<T>> factory)
87+
where T : new()
88+
=> new CollectionBenchmark<T>(size, repeat, factory, _ => new T()).Result;
8489
}

benchmarking/Benchmarks/CollectionParallelBenchmark.cs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Open.Diagnostics;
22
using System;
33
using System.Collections.Generic;
4+
using System.Diagnostics;
45
using System.Linq;
56
using System.Threading.Tasks;
67

@@ -19,17 +20,28 @@ protected override IEnumerable<TimedResult> TestOnceInternal()
1920
yield return TimedResult.Measure("Fill (.Add(item)) (In Parallel)",
2021
() => Parallel.For(0, TestSize, i => c.Add(_items[i])));
2122

22-
yield return TimedResult.Measure("Enumerate", () =>
23-
{
24-
// ReSharper disable once NotAccessedVariable
25-
int x = 0;
26-
// ReSharper disable once LoopCanBeConvertedToQuery
27-
foreach (T _ in c) { x++; }
28-
});
29-
30-
// It's obvious to note that you have to 'lock' a collection or acquire a 'snapshot' before enumerating.
31-
yield return TimedResult.Measure("Enumerate (In Parallel)",
32-
() => Parallel.ForEach(c, _ => { }));
23+
24+
yield return TimedResult.Measure("Enumerate (8 times)", () =>
25+
{
26+
for (int i = 0; i < 8; ++i)
27+
{
28+
// ReSharper disable once NotAccessedVariable
29+
int x = 0;
30+
// ReSharper disable once LoopCanBeConvertedToQuery
31+
foreach (T _ in c) { x++; }
32+
Debug.Assert(x == TestSize);
33+
}
34+
});
35+
36+
// It's obvious to note that you have to 'lock' a collection or acquire a 'snapshot' before enumerating.
37+
yield return TimedResult.Measure("Enumerate (8 times) (In Parallel)",
38+
() =>
39+
{
40+
for (int i = 0; i < 8; ++i)
41+
{
42+
Parallel.ForEach(c, _ => { });
43+
}
44+
});
3345

3446
yield return TimedResult.Measure(".Contains(item) (In Parallel)",
3547
() => Parallel.For(0, TestSize * 2, i => { bool _ = c.Contains(_items[i]); }));

benchmarking/Benchmarks/DictionaryParallelBenchmark.cs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,26 @@ protected override IEnumerable<TimedResult> TestOnceInternal()
3636
Debug.Assert(c[i] == _items[i].Value);
3737
#endif
3838

39-
yield return TimedResult.Measure("Enumerate", () =>
39+
yield return TimedResult.Measure("Enumerate (8 times)", () =>
4040
{
41-
// ReSharper disable once NotAccessedVariable
42-
int x = 0;
43-
// ReSharper disable once LoopCanBeConvertedToQuery
44-
foreach (var _ in c) { x++; }
45-
Debug.Assert(x == testSize);
41+
for (int i = 0; i < 8; ++i)
42+
{
43+
// ReSharper disable once NotAccessedVariable
44+
int x = 0;
45+
// ReSharper disable once LoopCanBeConvertedToQuery
46+
foreach (var _ in c) { x++; }
47+
Debug.Assert(x == TestSize);
48+
}
4649
});
4750

48-
yield return TimedResult.Measure("Enumerate (In Parallel)",
49-
() => Parallel.ForEach(c, _ => { }));
51+
yield return TimedResult.Measure("Enumerate (8 times) (In Parallel)",
52+
() =>
53+
{
54+
for (int i = 0; i < 8; ++i)
55+
{
56+
Parallel.ForEach(c, _ => { });
57+
}
58+
});
5059

5160
yield return TimedResult.Measure(".Contains(item) (In Parallel)",
5261
() => Parallel.For(0, testSize * 2, i =>
@@ -57,7 +66,7 @@ protected override IEnumerable<TimedResult> TestOnceInternal()
5766
}));
5867

5968
object[] items = Enumerable.Range(0, mixSize).Select(_ => new object()).ToArray();
60-
yield return TimedResult.Measure("Random Set/Get", () =>
69+
yield return TimedResult.Measure("50/50 Set/Get (In Parallel)", () =>
6170
{
6271
for (int i = 0; i < testSize; i++)
6372
{

benchmarking/Program.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static void Main()
2020
//TestEntry.Test1();
2121
//TestEntry.Test2();
2222
//QueueTests();
23-
//ListTests();
23+
ListTests();
2424
DictionaryTests();
2525

2626
Console.Beep();
@@ -145,8 +145,8 @@ static void ListTests()
145145
Console.WriteLine("::: Synchronized Lists :::\n");
146146
var report = new BenchmarkConsoleReport<Func<IList<object>>>(100000, ListParallelBenchmark.Results);
147147

148-
report.AddBenchmark("TrackedList",
149-
_ => () => new TrackedList<object>());
148+
//report.AddBenchmark("TrackedList",
149+
// _ => () => new TrackedList<object>());
150150
report.AddBenchmark("ConcurrentList",
151151
_ => () => new ConcurrentList<object>());
152152
report.AddBenchmark("LockSynchronizedList",

source/ListWrapper.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
using System.Runtime.CompilerServices;
33

44
namespace Open.Collections;
5-
public class ListWrapper<T> : CollectionWrapper<T, IList<T>>, IList<T>
5+
public class ListWrapper<T, TList>
6+
: CollectionWrapper<T, TList>, IList<T>
7+
where TList : class, IList<T>
68
{
7-
public ListWrapper(int capacity = 0)
8-
: base(new List<T>(capacity), true)
9-
{
10-
}
11-
12-
public ListWrapper(IList<T> source, bool owner = false)
9+
public ListWrapper(TList source, bool owner = false)
1310
: base(source, owner)
1411
{
1512
}
@@ -36,3 +33,17 @@ public virtual void Insert(int index, T item)
3633
public virtual void RemoveAt(int index)
3734
=> InternalSource.RemoveAt(index);
3835
}
36+
37+
public class ListWrapper<T>
38+
: ListWrapper<T, IList<T>>
39+
{
40+
public ListWrapper(IList<T> source, bool owner = false)
41+
: base(source, owner)
42+
{
43+
}
44+
45+
public ListWrapper(int capacity = 0)
46+
: base(new List<T>(capacity))
47+
{
48+
}
49+
}

0 commit comments

Comments
 (0)