函数参数传递中的C#7.2 const与referenced(in)只读字段

时间:2018-08-01 12:17:12

标签: c# .net .net-core c#-7.2

假设我有一个与以下课程有关的课程: const

private const decimal x = 2.0m;

只读字段

private readonly decimal y = 2.0m;

具有此签名的方法

void Method1(in decimal x)

如果我使用const x Method1(x)调用Method1,我假设x的值将按值传递,而当我将Method1与只读y一起使用Method1(in y)时,该值将通过只读引用传递。因此,我的期望是,性能更高的是用作“伪” const的只读字段。我错了?我怀疑编译器内部将使用const或clr对其进行优化,以使其成为通过引用传递的只读字段而具有出色的性能。

2 个答案:

答案 0 :(得分:2)

我已经进行了测试,获胜者是in传入的只读字段,这是使用i7 8700k处理器执行的代码

class Test
{
    public const decimal x = 0.2m;
    public readonly decimal y = 0.2m;

    public void Method1(in decimal x)
    {
        Thread.MemoryBarrier();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var t = new Test();

        var sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < 100000000; i++)
        {
            t.Method1(in t.y);
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedTicks);
        sw.Restart();
        for (var i = 0; i < 100000000; i++)
        {
            t.Method1(Test.x);
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedTicks);
        Console.ReadLine();
     } 
}

以t.Method1(在t.y中)调用的方法;消耗了11606428个s 作为t.Method1(Test.x);调用的方法;消耗了16963941滴答声

因此,在这种情况下,没有针对const进行优化

答案 1 :(得分:2)

是的,可能 readonly 选项的性能更高,但是对于是否将这种性能提升视为有意义的问题,仍有待商

为什么?

const版本实际上将在每次调用该方法时运行十进制构造函数,而readonly / in版本将仅将引用复制到以前创建的十进制实例。后者显然更快。

您可以通过简单地检查IL来验证这一点:

  • 常量版本:

    IL_0001: ldc.i4.s 20
    IL_0003: ldc.i4.0
    IL_0004: ldc.i4.0
    IL_0005: ldc.i4.0
    IL_0006: ldc.i4.1
    IL_0007: newobj instance void [mscorlib]System.Decimal::.ctor(int32, int32, int32, bool, uint8)
    IL_000c: call instance bool C::Method2(valuetype [mscorlib]System.Decimal)
    
  • 只读版本:

    IL_0002: ldflda valuetype [mscorlib]System.Decimal C::dd
    IL_0007: call instance bool C::Method1(valuetype [mscorlib]System.Decimal&)
    IL_000c: pop
    

也就是说,我不太确定为什么将const与性能联系在一起。 const是一种在代码中传达给定值永远不会改变的方法。 const并不意味着,使用常量存储的此值将在使用时表现更好。

除非您确实有一个由经验证明的性能问题可以通过这种边际(最佳)优化解决,否则逻辑上为常数的值应为const,而逻辑上为只读的变量值应为readonly,所有其他注意事项均应忽略。如果您的案例是前者,那么请在代码中清楚地说明为什么将逻辑常数值实现为只读字段。