You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何C#的in关键字会导致性能下降?

为什么C#中in关键字传递结构体的性能比ref和值传递更差?

我在测试提升C#性能的方法时,尝试用ref和in关键字以引用方式传递结构体,结果发现ref的性能优于普通值传递,但in的性能反而比前两者都差,测试代码和结果如下:

测试代码

using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        const int Iterations = 10000000;
        Point3D point = new Point3D(3, 4, 5);

        Stopwatch sw = new Stopwatch();

        // 测试值传递
        sw.Start();
        for (int i = 0; i < Iterations; i++)
        {
            ComputeLengthByValue(point);
        }
        sw.Stop();
        Console.WriteLine($"Elapsed time without 'in': {sw.ElapsedMilliseconds} ms");

        // 测试in关键字传递
        sw.Reset();
        sw.Start();
        for (int i = 0; i < Iterations; i++)
        {
            ComputeLengthByIn(in point);
        }
        sw.Stop();
        Console.WriteLine($"Elapsed time with 'in': {sw.ElapsedMilliseconds} ms");
      
        // 测试ref关键字传递
        sw.Reset();
        sw.Start();
        for (int i = 0; i < Iterations; i++)
        {
            ComputeLengthByRef(ref point);
        }
        sw.Stop();
        Console.WriteLine($"Elapsed time with 'ref': {sw.ElapsedMilliseconds} ms");
    }

    public static double ComputeLengthByValue(Point3D point)
    {
        return point.ComputeLength();
    }

    public static double ComputeLengthByIn(in Point3D point)
    {
        return point.ComputeLength();
    }

    public static double ComputeLengthByRef(ref Point3D point)
    {
        return point.ComputeLength();
    }
}

public struct Point3D
{
    public double X;
    public double Y;
    public double Z;

    public Point3D(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public double ComputeLength()
    {
        return Math.Sqrt(X * X + Y * Y + Z * Z);
    }
}

测试结果

参数关键字耗时
无in或ref(值传递)11 ms
使用in14 ms
使用ref10 ms

原因分析

1. 防御性副本的额外开销

in参数是只读引用,编译器会确保它不会被修改。但你的Point3D.ComputeLength()方法没有标记为readonly,编译器默认会假设这个实例方法可能修改结构体成员。为了保证in参数的只读性,编译器会在调用ComputeLength()时生成一个防御性副本——相当于把in引用的结构体复制一份再调用方法,额外增加了复制开销,导致性能下降。

而ref是可写引用,编译器不需要做这种防护,直接通过引用访问结构体成员;值传递本身就是复制一次结构体,开销远小于in的“引用+防御性复制”两步操作。

2. 小型结构体的场景不适合用in

你的Point3D是仅包含三个double的小型结构体(大小24字节),值传递的复制开销本来就极小,in的引用传递优势完全体现不出来,反而因为防御性副本拖慢了性能。in的真正优势是传递大型结构体(比如几十、上百字节的结构体)时,避免值传递的大量复制操作。

解决方法

把ComputeLength()方法标记为readonly,告诉编译器这个方法不会修改结构体成员,这样就不会生成防御性副本,in的性能就能和ref持平:

public readonly double ComputeLength()
{
    return Math.Sqrt(X * X + Y * Y + Z * Z);
}

内容的提问来源于stack exchange,提问作者Captain Quack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 21:45:11