在C#中,使用const或readonly修饰符对字段有性能优势吗?

10

仅使用私有变量时,相比于常规可修改字段,使用constreadonly字段是否有性能上的优势?

例如:

public class FooBaar
{
     private string foo = "something";
     private const string baar = "something more"

     public void Baaz()
     {
         //access foo, access baar
     }
}
在上面的示例中,您可以看到有两个字段:foobaar。这两个字段在类外部不可访问,那么为什么许多人更喜欢在这里使用const,而不是只使用privateconst是否提供任何性能优势?
此问题先前被社区关闭,因为人们误解了这个问题为“在性能方面,constreadonly之间有什么区别?”,这个问题已经在这里得到回答:What is the difference between const and readonly?
但实际上我的意思是,“使用constreadonly是否比不使用它们带来任何性能优势”。

4
当你对微观优化感到厌倦时,总还可以进行纳米级别的优化。 - H H
@Rusi Nova - 你的第一个字符串不是只读的,而是私有的。要使其只读,应该写成'private readonly string foo="something"'。 - iandotkelly
3
@Henk - 我有些不同意。当速度成为问题时,应该怎么做?这个问题是关于性能的,答案不能简单地忽略这一点。Spender的回答是非常好的建议,但并不是真正回答这个问题的答案。 - iandotkelly
2
如果涉及性能问题,唯一明智的答案是:使用分析器找到问题。很少会是(缺少)readonly或const。 - H H
1
不同的答案 - const 是,readonly 不是。 - iandotkelly
显示剩余3条评论
3个回答

26

const会被编译器优化为内联到您的代码中,而readonly无法内联。但是,并非所有类型都可以定义为常量 - 在这种情况下,您必须将它们定义为readonly。

因此,如果您需要在代码中使用常量值,应首先尝试使用const,如果不行,则可以使用readonly来保证安全性,但不能获得性能优势。

例如:

public class Example
{
    private const int foo = 5;
    private readonly Dictionary<int, string> bar = new Dictionary<int, string>();

    //.... missing stuff where bar is populated

    public void DoSomething()
    {
       Console.Writeline(bar[foo]);

       // when compiled the above line is replaced with Console.Writeline(bar[5]);
       // because at compile time the compiler can replace foo with 5
       // but it can't do anything inline with bar itself, as it is readonly
       // not a const, so cannot benefit from the optimization
    }
}

0
我也在想同样的问题,并且我使用了一个工具来检查使用静态和只读修饰符的结果IL输出。
看看这个例子:
public class C {

    const string test = "stuff";
    private static string test2 = "stuff2";

    public static void M() {
        System.Console.WriteLine(test);
        System.Console.WriteLine(test2);
    }
}

而且M()的IL输出为:
 IL_0000: nop
 IL_0001: ldstr "stuff"
 IL_0006: call void [System.Console]System.Console::WriteLine(string)
 IL_000b: nop
 IL_000c: ldsfld string C::test2
 IL_0011: call void [System.Console]System.Console::WriteLine(string)
 IL_0016: nop
 IL_0017: ret

目前的硬件上不太可能对性能产生任何差异,但似乎常量在执行指令进入CPU时会将数据传递到word中,而静态引用会携带一个内存指针,使CPU在某个寄存器/L1缓存等中检索值。

完整输出请参见:https://gist.github.com/VagnerGon/e8f48a652cc4f234c2ab060a5eeb7d2e


-3
我不会过于担心这些结构的性能,除非你遇到需要进行此类测量的关键代码。它们存在是为了确保代码的正确性,而不是出于性能原因。

32
很好的建议,我也不担心表现问题——但这并没有回答问题。 - iandotkelly
9
这并没有回答问题,并且假设性能关键的代码不会被编写。这绝对不应该成为被采纳的答案。 - Daniel
@Daniel:经验告诉我,当问题是“哪个更快,语言特性X还是语言特性Y”时,人们往往会优先考虑错误的调查。 “性能优势”可以轻松地由OP测量,并不真正代表应该在SO上提出的问题。那些寻找这个问题答案的人最好被提醒,他们很可能用错误的心态看待事情。 - spender
4
他问的不是那个问题,这个问题是否应该在这里也不是问题所在。如果我们有一个糟糕的问题,难道我们也必须有一个糟糕的答案吗?这个回答作为评论会更好,因为它就是一个评论。实际上,下面有一个更详细的、能提供更多信息的答案被埋没了。 - Daniel
@Daniel:没错。也许你可以提醒一下楼主标记其他答案,那么我就很乐意把这个答案降级为评论。在那之前,“你不能删除已接受的答案”。 - spender
做了就是做了。这是一个非常古老的问题。我只是在回答SO提示我下投票的原因。 - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接