C# 当操作为O(1)时,是否值得缓存.Count(或.Count())的结果?
如果在实现ICollection的对象上多次使用.Count或.Count()(因此计算复杂度为O(1),除非它被重写),那么它的性能是否更好(而不是内存方面),哪怕只是很小的差异,要将值缓存在临时变量中,而不是每次需要时都访问属性值?否,不需要;使用临时变量没有任何好处。此外,如果正在缓存计数,则如果集合集发生更改,则可能会导致计数不正确。如果您确定C# 当操作为O(1)时,是否值得缓存.Count(或.Count())的结果?,c#,.net,performance,count,C#,.net,Performance,Count,如果在实现ICollection的对象上多次使用.Count或.Count()(因此计算复杂度为O(1),除非它被重写),那么它的性能是否更好(而不是内存方面),哪怕只是很小的差异,要将值缓存在临时变量中,而不是每次需要时都访问属性值?否,不需要;使用临时变量没有任何好处。此外,如果正在缓存计数,则如果集合集发生更改,则可能会导致计数不正确。如果您确定.count()现在和在功能中要执行的操作,则答案是否。答案是是如果。Count()是一些可能更改的实现。假设您使用一些可能不是O(1)的Link
.count()
现在和在功能中要执行的操作,则答案是否。答案是是如果。Count()
是一些可能更改的实现。假设您使用一些可能不是O(1)的LinkedList更改了实现 是的,它可能会(稍微)快一些,因为方法调用的开销、关联的错误检查以及(在Count()的情况下)ICollection的动态类型检查都有一定的开销
但是值得吗?这完全取决于你和你的申请。如果你处于一个非常紧密的内部循环中,这可能是值得的。然后,在最近的.NET运行时上,这种琐碎的属性在这种情况下可能会被内联
一如既往,让您的探查器告诉您应用程序中的热点在哪里。对不起,认为
ICollection.Count
是O(1)
是错误的。这在道德上是应该的,但不能保证:
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));
public集合:ICollection{
私有只读ICollection集合;
私有只读函数slowgrowing函数;
公众藏品(
i收集,
函数(慢行函数)
{
this.collection=collection;
this.slowGrowingFunction=slowGrowingFunction;
}
公共整数计数{
得到{
Sleep(1000*this.slowgrowing函数(this.collection.Count));
返回此.collection.Count;
}
}
//其他方法在ICollection的集合上包装方法
}
ICollection集合=
新集合(集合,n=>Ackermann(4,n));
哦,不,evilCollection.Count
是O(阿克曼(4,n))
也就是说,除非我知道我可能会进入邪恶的集合,否则我不会担心这个问题,我发现这是一个严重的性能瓶颈。请记住,代码不太清晰,可能不太正确(缓存结果后的计数更新是多少?),等等
只需编写最简单的代码即可(使用
ICollection.Count
)。如果且仅当它是应用程序中的性能瓶颈时,我才会担心如何调整它。直接回答这个问题,即使是O(1)操作也可能需要很长时间才能完成;只是不管收藏量有多大,都需要相同的时间。缓存结果并将其读回总是很快的,但不能保证比任何给定的O(1)操作都快。你首先需要一些时间;) 这是一个修辞问题还是某种哲学问题?前传:@Jason-是的,你可以,这就是为什么我说“几乎总是”。但那将是一个写得非常糟糕的类,表现非常糟糕,所以你可能不会。@Jason-你完全错了。一个人可以在代码中做很多坏事。这并不意味着有人会这样做,即使有人这样做了,他们的代码也会因为工作不好而被丢弃。@Jason:“如果我能为每一个不是邪恶的人创造一个邪恶的,那么邪恶的人至少和不邪恶的人一样多。”这句话意味着你有能力编写糟糕的代码,意味着坏的集合至少和好的集合一样多,这是完全错误的。大多数程序员永远不会写这样的邪恶的集合,即使你也不会。至少我希望如此!因此,你认为存在的邪恶收藏和美好收藏一样多的说法是完全错误的。任何人都不应该写这样的收藏。你甚至承认这是邪恶的。您每次必须计数的集合将正确定义为可枚举的集合,而不是集合或列表。您没有抓住要点。假设ICollection.Count
是O(1)
,这是错误的。这是错误的,因为我可以举一个不正确的例子。这不是唯一的例子(这太离谱了),甚至可能有真实世界的例子。但是,如果您正在对接口ICollection
进行编码,那么您不知道会发生什么。您不知道这是一个集合
,还是另一个使i集合。Count
不是O(1)
。因此,你不能全盘假设,ICollection.Count
是O(1)
,然后从这个错误的假设开始胡闹。杰森,是的,你可以这样假设。所有代码都需要运行和测试。当您的邪恶集合表现不佳时(不仅在OP的使用中,而且在许多常见用途中),它将被丢弃或进行防御编码,例如通过编写一个正确缓存计数的包装器类。@AresAvatar:您不能这样假设。这是我的方法。我是一个API作者,或者是一个框架作者,或者谁知道呢。在我的API中,我提供了这个方法:publicvoidm(ICollection集合)
我不知道collection
将是什么。没有一个我不能在我的方法M
中假设collection.Count
是O(1)
。我不能,因为我不知道运行时的集合是什么。你不明白吗?我认为你在这件事上是错的,我认为我们不会同意。我不作进一步评论。