Модификатор in
помогает повысить производительность, избегая ненужных копий типов значений при вызове метода.Обратите внимание, что типы значений (то есть структуры) на самом деле не являются автоматически неизменяемыми (но компилятор C # создает видимость неизменности, делая «защитные копии» и затем перезаписывая весь родительский элемент struct
при установке значения свойства, это объясняется встатья, на которую вы ссылались).
Учитывая, что структуры полностью копируются в вызовах методов, если вы не используете in
(или out
/ ref
), вы можете улучшить производительность толькопередача указателя на объект структуры выше в стеке вызовов, потому что указатель (ссылка в .NET) меньше, чем структура, но это позволяет избежать копирования только в том случае, если структура также действительно неизменна.
Встроенные типы значений C # (Int16
, Int32
, Double
, UInt64
и т. Д.) Все меньше (или имеют тот же размер, что и) указатель в 64-битных системах (кроме * 1014)* это 128-битный тип и String
(это ссылочный тип), что означает, что использование модификатора in
с этими типами дает нулевую выгоду.Вы также пострадаете от снижения производительности из-за затрат на разыменование указателя, что также может привести к потере кэш-памяти процессора .
. Рассмотрим несколько различных сценариев ниже (все примеры предполагают 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
будет изменено.