Skip to content

Commit 82819e0

Browse files
committed
[Distinct] use visitor to improve performance.
1 parent f7ac5c1 commit 82819e0

File tree

3 files changed

+51
-12
lines changed

3 files changed

+51
-12
lines changed

Documents/BenchmarksResults/Distinct.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@
77
``` ini
88

99
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
10-
Intel Core i7-8750H CPU 2.20GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
11-
.NET Core SDK=5.0.101
12-
[Host] : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
13-
DefaultJob : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
10+
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
11+
.NET Core SDK=5.0.202
12+
[Host] : .NET Core 5.0.5 (CoreCLR 5.0.521.16609, CoreFX 5.0.521.16609), X64 RyuJIT
13+
DefaultJob : .NET Core 5.0.5 (CoreCLR 5.0.521.16609, CoreFX 5.0.521.16609), X64 RyuJIT
1414

1515

1616
```
1717
| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
1818
|----------------------- |---------:|--------:|--------:|------:|--------:|--------:|--------:|----------:|
19-
| Linq | 485.9 μs | 2.88 μs | 2.70 μs | 1.00 | 90.8203 | 90.8203 | 90.8203 | 524784 B |
20-
| StructLinq | 176.9 μs | 3.32 μs | 3.41 μs | 0.36 | - | - | - | 32 B |
21-
| StructLinqZeroAlloc | 173.8 μs | 0.75 μs | 0.70 μs | 0.36 | - | - | - | - |
22-
| StructLinqZeroAllocSum | 160.3 μs | 0.57 μs | 0.53 μs | 0.33 | - | - | - | - |
19+
| Linq | 544.3 μs | 7.98 μs | 7.08 μs | 1.00 | 90.8203 | 90.8203 | 90.8203 | 524784 B |
20+
| StructLinq | 215.7 μs | 2.56 μs | 2.14 μs | 0.40 | - | - | - | 32 B |
21+
| StructLinqZeroAlloc | 220.7 μs | 0.77 μs | 0.64 μs | 0.41 | - | - | - | - |
22+
| StructLinqZeroAllocSum | 152.6 μs | 0.53 μs | 0.44 μs | 0.28 | - | - | - | - |

src/StructLinq.Tests/DistinctTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,21 @@ public void ShouldEquals()
3030
.ToEnumerable();
3131
Assert.Equal(expected, value);
3232
}
33+
34+
[Fact]
35+
public void ToArrayShouldEquals()
36+
{
37+
var expected = Enumerable.Range(0, 100)
38+
.Select(x => x % 10)
39+
.Distinct()
40+
.ToArray();
41+
42+
var value = Enumerable.Range(0, 100)
43+
.Select(x => x % 10)
44+
.ToStructEnumerable()
45+
.Distinct(x => x)
46+
.ToArray();
47+
Assert.Equal(expected, value);
48+
}
3349
}
3450
}

src/StructLinq/Distinct/DistinctEnumerable.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,36 @@ public DistinctEnumerator<T, TEnumerator, TComparer> GetEnumerator()
3838
public VisitStatus Visit<TVisitor>(ref TVisitor visitor)
3939
where TVisitor : IVisitor<T>
4040
{
41-
foreach (var input in this)
41+
var distinctVisitor = new DistinctVisitor<TVisitor>(capacity, bucketPool, slotPool, comparer, ref visitor);
42+
var visitStatus = enumerable.Visit(ref distinctVisitor);
43+
visitor = distinctVisitor.visitor;
44+
distinctVisitor.Dispose();
45+
return visitStatus;
46+
}
47+
48+
private struct DistinctVisitor<TVisitor> : IVisitor<T>
49+
where TVisitor : IVisitor<T>
50+
{
51+
public TVisitor visitor;
52+
private PooledSet<T, TComparer> set;
53+
54+
public DistinctVisitor(int capacity, ArrayPool<int> bucketPool, ArrayPool<Slot<T>> slotPool, TComparer comparer, ref TVisitor visitor)
4255
{
43-
if (!visitor.Visit(input))
44-
return VisitStatus.VisitorFinished;
56+
this.visitor = visitor;
57+
set = new PooledSet<T, TComparer>(capacity, bucketPool, slotPool, comparer);
4558
}
4659

47-
return VisitStatus.EnumeratorFinished;
60+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
61+
public bool Visit(T input)
62+
{
63+
return !set.AddIfNotPresent(input) || visitor.Visit(input);
64+
}
65+
66+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
67+
public void Dispose()
68+
{
69+
set.Dispose();
70+
}
4871
}
4972
}
5073
}

0 commit comments

Comments
 (0)