我已经在MSDN上阅读了article。它解释了为什么“ in”仅应与自定义只读结构一起使用,否则会导致性能下降。但是,我不太了解如何对原始类型使用“ in”。由于C#中所有内置值类型都是不可变的,这是否意味着与通过值传递值相比,使用“ in”修饰符通过引用传递它们会稍微改善性能?
示例:
public class Product
{
private readonly int _weight;
private readonly decimal _price;
public Product(in decimal price, in int weight)
{
_price = price;
_weight = weight;
}
}
vs
public class Product
{
private readonly int _weight;
private readonly decimal _price;
public Product(decimal price, int weight)
{
_price = price;
_weight = weight;
}
}
答案 0 :(得分:3)
in
修饰符通过在调用方法时避免不必要的值类型副本来提高性能。请注意,值类型(即结构)实际上并不是自动不可变的(但是C#编译器通过设置“防御性副本”,然后在设置属性值时覆盖整个父struct
,确实给出了不可变性的外观,这是在您链接到的文章中进行了解释)。
鉴于如果您不使用in
(或out
/ ref
),则在方法调用中完整复制结构,可以通过仅传递一个指针来提高性能。指针栈(.NET中的引用)比结构小,因此它是调用栈中较高级别的结构对象,但这仅在结构真正不可变的情况下才避免复制。
C#的内置值类型(Int16
,Int32
,Double
,UInt64
等)都小于指针(或与指针大小相同)在64位系统上(除了Decimal
是128位类型,而String
是引用类型),这意味着将in
修饰符与这些类型。指针取消引用会导致性能下降,这也可能导致处理器memory cache miss。
请考虑以下一些不同的情况(所有示例均假设使用x64,并且没有优化方法会更改方法调用或调用约定的语义):
public static void Main()
{
Int32 value = 123; // 4 bytes
Foo( in value ); // Get an 8-byte pointer to `value`, then pass that
}
public static void Foo( in Int32 x ) { ... }
性能受到影响,因为现在计算机传递的8字节指针值也需要取消引用,而不是可以立即使用的4字节值。
public struct MyBigStruct
{
public Decimal Foo;
public Decimal Bar;
public Decimal Baz;
}
public static void Main()
{
MyBigStruct value; // 48 bytes
Foo( in value ); // Get an 8-byte pointer to `value`, then pass that
}
public static void Foo( in MyBigStruct x ) { ... }
可能会提高性能,因为计算机传递的是8字节的指针值而不是复制48字节的值,但是指针取消引用 可能比复制多余的32字节要贵。您应该在运行时进行概要分析,以决定是否值得进行更改。这也会使x
中的Foo
不可变,因为否则将修改value
中的Main
。