модификатор "in" с примитивными типами значений? - PullRequest
0 голосов
/ 26 октября 2018

Я прочитал статью на MSDN.Это объясняет, почему «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;
    }
}

против

public class Product
{
    private readonly int _weight;
    private readonly decimal _price;

    public Product(decimal price, int weight)
    {
        _price = price;
        _weight = weight;
    }
}

1 Ответ

0 голосов
/ 26 октября 2018

Модификатор 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 будет изменено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...