StructLinq
在C#中实现LINQ概念,使用结构体来大幅减少内存分配并提高性能。
引入IRefStructEnumerable
以提高当元素为大型结构体时的性能。
安装
此库通过NuGet分发。
要安装StructLinq
:
PM> Install-Package StructLinq
使用
StructLinq
大量使用泛型概念和结构体"特化"。
using StructLinq;
int[] array = new [] {1, 2, 3, 4, 5};
int result = array
.ToStructEnumerable()
.Where(x => (x & 1) == 0, x=>x)
.Select(x => x *2, x => x)
.Sum();
x=>x
用于避免装箱(和分配)并帮助推断泛型类型参数。
你还可以通过为Where谓词和select函数使用结构体来提高性能。
性能
所有基准测试结果在这里。 例如,以下LINQ序列:
list
.Where(x => (x & 1) == 0)
.Select(x => x * 2)
.Sum();
可以替换为:
list
.ToStructEnumerable()
.Where(x => (x & 1) == 0)
.Select(x => x * 2)
.Sum();
或者如果你想要零分配,可以使用:
list
.ToStructEnumerable()
.Where(x => (x & 1) == 0, x=>x)
.Select(x => x * 2, x=>x)
.Sum(x=>x);
或者如果你想要零分配和更好的性能,可以使用:
var where = new WherePredicate();
var select = new SelectFunction();
list
.ToStructEnumerable()
.Where(ref @where, x => x)
.Select(ref @select, x => x, x => x)
.Sum(x => x);
基准测试结果如下:
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-8750H CPU 2.20GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=5.0.101
[Host] : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
DefaultJob : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
方法 | 平均值 | 误差 | 标准差 | 比率 | Gen 0 | Gen 1 | Gen 2 | 分配 |
---|---|---|---|---|---|---|---|---|
LINQ | 65.116 μs | 0.6153 μs | 0.5756 μs | 1.00 | - | - | - | 152 B |
StructLinqWithDelegate | 26.146 μs | 0.2402 μs | 0.2247 μs | 0.40 | - | - | - | 96 B |
StructLinqWithDelegateZeroAlloc | 27.854 μs | 0.0938 μs | 0.0783 μs | 0.43 | - | - | - | - |
StructLinqZeroAlloc | 6.872 μs | 0.0155 μs | 0.0137 μs | 0.11 | - | - | - | - |
StructLinq
明显比默认的LINQ
实现更快。
特性
对于IStructEnumerable
,可以使用foreach
进行零分配的鸭子类型。
BCL
以下类有StructLinq
扩展方法用于IStructEnumerable
:
IEnumerable<T>
T[]
List<T>
(在Struct.Linq.BCL
中)Dictionary<TKey, TValue>
(在Struct.Linq.BCL
中)Hashset<T>
(在Struct.Linq.BCL
中)ImmutableArray<T>
(在Struct.Linq.BCL
中)
转换器
以下转换器可用于:
ToArray
ToList
(在Struct.Linq.BCL
中)ToEnumerable
LINQ扩展
以下扩展可用于:
Aggregate
All
Any
Concat
Contains
Count
Distinct
(零分配)ElementAt
ElementAtOrDefault
Empty
Except
(零分配)First
FirstOrDefault
Intersect
(零分配)Last
LastOrDefault
Max
Min
OrderBy
(零分配)OrderByDescending
Range
Repeat
Reverse
(零分配)Select
SelectMany
Skip
SkipWhile
Sum
Take
TakeWhile
Union
(零分配)Where
其他扩展
LongCount
UIntCount
Order
TryFirst
IRefStructEnumerable
public interface IRefStructEnumerable<out T, out TEnumerator>
where TEnumerator : struct, IRefStructEnumerator<T>
{
TEnumerator GetEnumerator();
}
public interface IRefStructEnumerator<T>
{
bool MoveNext();
void Reset();
ref T Current { get; }
}
ref Current
允许避免复制。当T
是一个大型结构体时,这应该非常有用。
对于IRefStructEnumerable
,可以使用带ref
的foreach
进行零分配的鸭子类型。
BCL
以下类有StructLinq
扩展方法用于IRefStructEnumerable
:
T[]
List<T>
(在Struct.Linq.BCL
中)
转换器
以下转换器可用于:
ToArray
ToList
(在Struct.Linq.BCL
中)ToEnumerable
LINQ扩展
以下扩展可用于:
All
Any
Concat
Contains
Count
Distinct
ElementAt
ElementAtOrDefault
Except
First
FirstOrDefault
Intersect
Last
Select
Skip
SkipWhile
Sum
Take
TakeWhile
Union
Where
其他扩展
LongCount
UIntCount
TryFirst