6

ImmutableList从 NuGet 包Microsoft.Bcl.Immutable版本 1.0.34 和 1.1.22-beta体验 Microsoft 的一些意外性能

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

我对这些结果有点惊讶,因为我认为这ImmutableList会比复制 generic 更快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_ 删除所有项目只需不到 100 毫秒。这不是您在所有情况下都可以做的事情,但很高兴知道。

4

1 回答 1

5

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

为什么运行时间的巨大差异?可能,因为ImmutableList内部是树结构。这意味着要扫描列表,需要大量的指针取消引用和不可预测的分支和内存访问。那很慢。

于 2014-07-16T16:34:10.767 回答