关于c#:当操作是O(1)时,是否值得缓存.Count(或.Count())的结果?

Is it worth caching the result of .Count (or .Count()) when the operation is O(1)?

如果.count或.count()在实现ICollection的对象上多次使用(因此具有O(1)计算复杂性,除非它被重写),那么在性能方面(而不是内存方面)更好吗?即使存在非常小的差异,在临时变量中缓存值而不是每次访问属性值需要吗?


直接回答这个问题,即使是O(1)操作也需要很长时间才能完成;只是,无论收集的数据有多大,它总是需要相同的时间。缓存结果并将其读回将是快速的,总是,但不能保证比任何给定的O(1)操作都快。你首先需要一些时间安排;)


是的,它可能(非常轻微)更快,因为方法调用的开销、相关的错误检查以及(在count()的情况下)iCollection的动态类型检查都有一定的开销。

但是值得吗?这完全取决于您和您的应用程序。如果你处于一个非常紧密的内部循环中,这可能是值得的。然后,在最近的.NET运行时上,在这种情况下,这种琐碎的属性可能会被内联。

和往常一样,让分析器告诉您应用程序中的热点在哪里。


对不起,认为ICollection.CountO(1)是错误的。这在道义上应该是,但不能保证它是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public EvilCollection<T> : ICollection<T> {
    private readonly ICollection<T> collection;
    private readonly Func<int, int> slowGrowingFunction;
    public EvilCollection(
        ICollection<T> collection,
        Func<int, int> slowGrowingFunction)
    {
        this.collection = collection;
        this.slowGrowingFunction = slowGrowingFunction;
    }

    public int Count {
        get {
            Thread.Sleep(1000 * this.slowGrowingFunction(this.collection.Count));
            return this.collection.Count;
        }
    }

    // other methods wrap methods on collection for ICollection<T>
}

ICollection<T> evilCollection =
    new EvilCollection<T>(collection, n => Ackermann(4, n));

哦,不,evilCollection.CountO(Ackermann(4, n))

这就是说,除非我知道我可能加入了邪恶的集合,否则我不会担心这个问题,而且我发现它是一个重要的性能瓶颈。请记住,代码不太清楚,可能不太正确(缓存结果后,计数更新是什么?)等。

只需编写最简单有效的代码(使用ICollection.Count)。如果并且只有当它是应用程序中的性能瓶颈时,我才会担心对它进行调优。


如果您确定.Count()现在和在该特性中要做什么,那么答案是否定的。如果.Count()是一些可能会改变的实现,那么答案是肯定的。假设您使用某个LinkedList更改了实现,它可能不是O(1)。


不,不需要;使用临时变量没有好处。此外,如果您正在缓存计数,那么如果集合集发生更改,您将面临计数不正确的风险。