ImmutableListMicrosoft.Bcl.Immutable中的Remove方法

本文关键字:Immutable 中的 Remove 方法 Bcl Microsoft ImmutableList | 更新日期: 2023-09-27 18:13:22

从NuGet包Microsoft. bcl . immutable version 1.0.34和1.1.22-beta中体验Microsoft ImmutableList的一些意外性能

当从不可变列表中删除项时,性能非常慢。对于包含20000个整数值(1…20000)的ImmutableList,如果从20000到1开始删除,大约需要52秒才能从列表中删除所有项。如果我对一个通用的List<T>做同样的事情,我在每次删除操作后创建一个列表的副本,它需要大约500 ms.

我对这些结果感到有点惊讶,因为我认为ImmutableList将比复制通用List<T>更快,但也许这是意料之中的?

示例代码

// Generic List Test
var genericList = new List<int>();
var sw = Stopwatch.StartNew();
for (int i = 0; i < 20000; i++)
{
    genericList.Add(i);
    genericList = new List<int>(genericList);
}
sw.Stop();
Console.WriteLine("Add duration for List<T>: " + sw.ElapsedMilliseconds);
IList<int> completeList = new List<int>(genericList);
sw.Restart();
// Remove from 20000 -> 0.
for (int i = completeList.Count - 1; i >= 0; i--)
{
    genericList.Remove(completeList[i]);
    genericList = new List<int>(genericList);
}
sw.Stop();
Console.WriteLine("Remove duration for List<T>: " + sw.ElapsedMilliseconds);
Console.WriteLine("Items after remove for List<T>: " + genericList.Count);

// ImmutableList Test
var immutableList = ImmutableList<int>.Empty;
sw.Restart();
for (int i = 0; i < 20000; i++)
{
    immutableList = immutableList.Add(i);
}
sw.Stop();
Console.WriteLine("Add duration for ImmutableList<T>: " + sw.ElapsedMilliseconds);
sw.Restart();
// Remove from 20000 -> 0.
for (int i = completeList.Count - 1; i >= 0; i--)
{
    immutableList = immutableList.Remove(completeList[i]);
}
sw.Stop();
Console.WriteLine("Remove duration for ImmutableList<T>: " + sw.ElapsedMilliseconds);
Console.WriteLine("Items after remove for ImmutableList<T>: " + immutableList.Count);

更新

如果从ImmutableList的开头删除项,就像普通的foreach循环一样,那么性能要比好得多。然后,删除所有项所需的时间少于100毫秒。这不是在所有情况下都可以做的事情,但知道这一点是很好的。

ImmutableList<T>Microsoft.Bcl.Immutable中的Remove方法

Remove方法必须扫描整个列表才能找到要删除的元素。移除本身是O(1),因为只需要移除最后一个元素。两种算法都具有二次型性能。

为什么在运行时间上有如此大的差异?可能,因为ImmutableList内部是一个树形结构。这意味着扫描列表需要大量的指针解引用和不可预测的分支和内存访问。