在处理数十亿条记录时,选择最佳的数据结构是一个挑战。本文将探讨在非实时操作系统环境下,如何通过性能基准测试来确定最佳的数据结构。在阅读本文之前,请考虑以下要点:操作系统不是实时操作系统,因此将展示的是平均结果;二分查找(Binary Search)需要排序,而排序的时间复杂度在本研究中被忽略,可以使用任何方便的排序算法,并将其复杂度加到结果之上。
好的解决方案是在最小化时间成本的同时,提供最大的速度和容量。显然,由于工作操作系统不是实时操作系统,区分出了确定性的问题。但是,如果能想出一个更确定性的解决方案,那就再好不过了。
执行所有单元测试的机器具有以下硬件和软件配置:
本文将对C#.NET语言中处理大数据集合的性能进行基准测试,从容量、速度和时间成本的角度来探讨。选择的集合类型包括数组(Array)、列表(List)和字典(Dictionary)。
托管代码是由微软创造的一个术语,指的是在CLR(如.NET或Mono)的管理下执行的代码。有关托管代码和非托管代码的更多信息,请访问以下链接:
由于CLR的干扰,托管代码的执行可能不那么确定性,因此提供一个提供粗略估计的基准测试可能非常有用。然而,在考虑这个基准测试的结果之前,最好回答以下两个问题:
正如将从结果中看到的,每个集合的性能高度依赖于集合的大小和正在使用的算法,例如搜索。
请注意,所有测试都是在非实时操作系统中进行的。这意味着结果不是确定性的。为了克服这种非确定性结果,执行了100次所有测试,所以将看到的是100次迭代的平均时间。
考虑的操作是创建和搜索,因为这两个操作是最昂贵且最重要的。
以下方法展示了搜索测试的模式,如所见,考虑的总是最坏的情况,这意味着正在寻找的项目几乎在集合的末尾。搜索算法被包围在包含时钟的Monitor对象中,该对象在进入搜索主体之前开始,并在集合中找到项目后立即停止:
[TestMethod]
[TestCategory("Owner [C# Array]")]
public void FindByForInArry()
{
try
{
string find = mocklbl + (capacity - 1);
Monitor.Reset();
for (int j = 0; j < iteration; j++)
{
string found = "";
Monitor.Start();
for (int i = 0; i < capacity; i++)
{
if (array[i] == find)
{
found = array[i];
break;
}
}
Monitor.Stop();
Assert.AreEqual(find, found);
}
Monitor.LogAvgElapsed("FindByForInArray");
}
catch (Exception ex)
{
Monitor.WriteLog(ex.Message);
throw ex;
}
}
从上面的图表中,可以列出一些有趣的事实:
[TestMethod]
[TestCategory("Owner [C# Array]")]
public void FetchMockData(long capacity = 1000)
{
try
{
capacity = Monitor.BySize;
for (int j = 0; j < 100; j++)
{
Monitor.Reset();
Monitor.Start();
array = new string[capacity];
for (int i = 0; i < capacity; i++)
{
array[i] = mocklbl + i;
}
Monitor.Stop();
}
Monitor.WriteLog($"The creation of array took:{Monitor.AvgElapsedInMiliseconds}");
}
catch (Exception ex)
{
Monitor.WriteLog(ex.Message);
throw ex;
}
}