StructLinq linq性能优化

在C#中用结构体实现LINQ,以大幅减少内存分配并提高性能。引入IRefStructEnumerable,以提高元素为胖结构体(胖结构体是指结构体大小大于16Byte)时的性能。

1
2
PM> Install-Package StructLinq
# https://www.nuget.org/packages/StructLinq/

简单使用
下方就是一个简单的使用,用来求元素和。唯一不同的地方就是需要调用ToStructEnumerable方法。

1
2
3
4
5
6
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函数使用结构来提高性能。

性能

1
list.Where(x => (x & 1) == 0).Select(x => x * 2).Sum();

可以被替换为下面的代码:

1
list.ToStructEnumerable().Where(x => (x & 1) == 0).Select(x => x * 2).Sum();

或者你想零分配内存,可以像下面一样写(类型推断出来,没有装箱):

1
list.ToStructEnumerable().Where(x => (x & 1) == 0, x=>x).Select(x => x * 2, x=>x).Sum(x=>x);

如果想要零分配和更好的性能,可以像下面一样写:

1
2
3
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);

StructLinq在这些场景里比默认的LINQ实现快很多。

总结

在已经用上结构体的高性能场景,其实不建议使用LINQ了,因为LINQ本身它性能就存在瓶颈,它主要就是为了提升开发效率。建议直接使用普通循环。
如果一定要使用,那么建议大于8byte的结构体使用StructLinq的引用传递模式(ToRefStructEnumerable),这样可以把普通LINQ结构体的性能提升5倍以上,也能几乎不分配额外的空间。