我调查了性能下降,并将其跟踪到缓慢的HashSet。
我有带有可为空值的结构,用作主键。例如:
public struct NullableLongWrapper
{
private readonly long? _value;
public NullableLongWrapper(long? value)
{
_value = value;
}
}
我注意到创建A的HashSet<NullableLongWrapper>
过程非常缓慢。
这是使用BenchmarkDotNet的示例:(Install-Package BenchmarkDotNet
)
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
public class Program
{
static void Main()
{
BenchmarkRunner.Run<HashSets>();
}
}
public class Config : ManualConfig
{
public Config()
{
Add(Job.Dry.WithWarmupCount(1).WithLaunchCount(3).WithTargetCount(20));
}
}
public struct NullableLongWrapper
{
private readonly long? _value;
public NullableLongWrapper(long? value)
{
_value = value;
}
public long? Value => _value;
}
public struct LongWrapper
{
private readonly long _value;
public LongWrapper(long value)
{
_value = value;
}
public long Value => _value;
}
[Config(typeof (Config))]
public class HashSets
{
private const int ListSize = 1000;
private readonly List<long?> _nullables;
private readonly List<long> _longs;
private readonly List<NullableLongWrapper> _nullableWrappers;
private readonly List<LongWrapper> _wrappers;
public HashSets()
{
_nullables = Enumerable.Range(1, ListSize).Select(i => (long?) i).ToList();
_longs = Enumerable.Range(1, ListSize).Select(i => (long) i).ToList();
_nullableWrappers = Enumerable.Range(1, ListSize).Select(i => new NullableLongWrapper(i)).ToList();
_wrappers = Enumerable.Range(1, ListSize).Select(i => new LongWrapper(i)).ToList();
}
[Benchmark]
public void Longs() => new HashSet<long>(_longs);
[Benchmark]
public void NullableLongs() => new HashSet<long?>(_nullables);
[Benchmark(Baseline = true)]
public void Wrappers() => new HashSet<LongWrapper>(_wrappers);
[Benchmark]
public void NullableWrappers() => new HashSet<NullableLongWrapper>(_nullableWrappers);
}
结果:
方法 中位数| 缩放比例 ----------------- | ---------------- | --------- 长裤| 22.8682我们| 0.42 NullableLongs | 39.0337我们| 0.62 包装纸| 62.8877我们| 1.00 可空包装| 231,993.7278我们| 3,540.34
与具有a的结构Nullable<long>
相比,使用具有a的结构long
要慢3540倍!
以我为例,它使800ms和<1ms之间有所不同。
以下是BenchmarkDotNet的环境信息:
OS = Microsoft Windows NT 6.1.7601 Service Pack 1
处理器= Intel(R)CoreTM i7-5600U CPU 2.60GHz,ProcessorCount = 4
Frequency = 2536269 ticks,Resolution = 394.2799 ns,Timer = TSC
CLR = MS.NET 4.0 .30319.42000,Arch = 64位RELEASE [RyuJIT]
GC =并发工作站
JitModules = clrjit-v4.6.1076.0
表现不佳的原因是什么?