不可变对象中的Length属性

时间:2013-04-14 05:03:50

标签: c# performance

如果object是不可变的(我自己实现的对象),我应该使用属性为Length还是只读变量?如果object将Length作为属性,则会在for循环中失去一些性能。

for (int i = 0; i < myObject.Length; i++) // Length is readonly variable
{
    // some code
}

int len = myObject.Length; // Length is a property

for (int i = 0; i < len; i++)
{
    // some code
}

你有什么建议?

3 个答案:

答案 0 :(得分:3)

在这样的样本中,没有办法重要。 JIT不是简单get的可能性非常低。即使get没有内联,额外的函数调用也不会成为非常简单的代码之外的性能瓶颈。

为了说明我的意思,我在发布模式下运行了以下内容(如果你保留调试它将以不同的方式工作)。

private int Length { get; set; }
private int _length;
void Run()
{
    Length = int.MaxValue;
    _length = int.MaxValue;
    var watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < Length; i++)
    {
    }
    watch.Stop();
    Console.WriteLine("Elapsed: {0}ms", watch.ElapsedMilliseconds);
    watch.Restart();
    for (int i = 0; i < _length; i++)
    {
    }
    watch.Stop();
    Console.WriteLine("Elapsed: {0}ms", watch.ElapsedMilliseconds);
}

我运行了10次并获得了以下平均值:属性为743 ms,变量为740 ms。这种差异可能只是因为我的机器上发生的尝试次数和其他事情都很少。

现在,如果您通过属性关闭内联,您将获得时间差异:属性为4577毫秒,变量为775毫秒。现在这听起来像是一个巨大的差异(总时间的6倍),但请记住我的循环条件:20亿次迭代。这意味着差异大约是每个操作2 ns。换句话说,大约需要4个时钟周期,除了最极端的性能场景外,还不足以担心。

答案 1 :(得分:1)

除非你在这里有一些非常大的特殊数据集,所以你希望对循环进行大量的迭代,所以属性和变量之间的差异可能是微不足道的。

简单的选择是使用变量。使用属性将为您提供额外的好处,即能够在不更改类的签名的情况下稍后修改它的行为(例如,如果您想以某种新方式计算长度)。

另一个相关的好处可能是私下设置属性的能力(如果需要,可以在以后更改),但只能公开阅读。

我想我会因为这些原因去找房产。无论如何,我不会仅根据对性能的预期影响做出这种选择。

答案 2 :(得分:0)

将临时变量更改为查询是一个非常标准的重构。换句话说,强烈建议如果属性调用非常快,那么就不应该创建临时变量。它被称为'replaceTempWithQuery'。这是一个模糊的东西:

http://www.refactoring.com/catalog/replaceTempWithQuery.html

我强烈建议对每个进行编程的人进行重构。

作为编辑添加:我为此得到了投票,但过早的优化确实是值得避免的 - 我只建议修复带有临时值的查询,如果它产生非常明显的问题。

A famous quote from Donald Knuth: "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil"。无论如何,这是一个选择问题,除非你有很多代码维护者。然后,维护时间通常会对您的优化/设计选择产生重大影响。