Зачем когда-либо использовать модификатор параметра "in" в C #? - PullRequest
0 голосов
/ 15 октября 2018

Итак, я (кажется, я) понимаю, что делает модификатор параметра in.Но то, что он делает, кажется довольно избыточным.

Обычно я думаю, что единственная причина использования ref состоит в том, чтобы изменить вызывающую переменную, что явно запрещенона in.Таким образом, передача по ссылке in кажется логически эквивалентной передаче по значению.

Есть ли какое-то преимущество в производительности?Я был убежден, что с внутренней стороны параметр ref должен, по крайней мере, копировать физический адрес переменной, который должен быть того же размера, что и любая типичная ссылка на объект.

Итак, тогда преимущество заключается только в более крупных структурах или есть какая-то закулисная оптимизация компилятора, которая делает его привлекательным в других местах?Если последнее, почему бы мне не сделать каждый параметр in?

Ответы [ 5 ]

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

передача по ссылке in кажется логически эквивалентной передаче по значению.

Правильно.

Есть ли какое-то преимущество в производительности?

Да.

Я считал, что на стороне сервера, параметр ref должен по крайней мере копировать физический адрес переменной,который должен быть того же размера, что и любая типичная ссылка на объект.

Не существует требования о том, чтобы ссылка на объект и ссылка на переменную имели одинаковый размер,и не существует требования , которое либо является размером машинного слова, но да, на практике оба являются 32-битными на 32-битных машинах и 64-битными на 64-битных машинах.

Что вы думаете о «физическом адресе», мне неясно. В Windows мы используем виртуальных адресов , а не физических адресов в коде режима пользователя.При каких возможных обстоятельствах вы представляете, что физический адрес имеет значение в программе на C #, мне любопытно знать.

Нет также требования о том, что ссылка любого вида должна быть реализована.как виртуальный адрес хранилища.Ссылки могут быть непрозрачными дескрипторами в таблицы GC в соответствующей реализации спецификации CLI.

- это преимущество только в больших структурах?

Снижение стоимости прохождения больших структур мотивирующий сценарий для функции.

Обратите внимание, что нет гарантии, что in сделает любую программу на самом деле быстрее, а может замедлить работу программ. На все вопросы об эффективности необходимо ответить эмпирическим исследованием .Существует очень мало оптимизаций, которые всегда выигрывают ;Это не оптимизация «всегда выигрывать».

Есть ли какая-то закулисная оптимизация компилятора, которая делает его привлекательным в других местах?

Компилятору и среде выполнения разрешено выполнять любую оптимизацию, которую они выбирают, если это не нарушает правила спецификации C #.Насколько мне известно, такая оптимизация для in параметров еще не реализована, но это не исключает возможности такой оптимизации в будущем.

почему я не должен делать каждый параметр входным?

Итак, предположим, что вы указали параметр int вместо параметра in int.Какие расходы налагаются?

  • на сайте вызова теперь требуется переменная , а не значение
  • переменная не может быть зарегистрирована.Тщательно настроенная схема распределения регистров джиттера только что добавила в него гаечный ключ.
  • код на сайте вызовов больше, потому что он должен взять ссылку на переменную и поместить ее в стек, тогда как прежде чем он могпросто поместите значение в стек вызовов
  • кода большего размера, что означает, что некоторые инструкции по быстрому переходу теперь могут стать инструкциями по длинному переходу, поэтому снова код становится больше.Это влияет на все виды вещей.Кеши заполняются быстрее, у джиттера есть больше работы, джиттер может решить не выполнять определенную оптимизацию при больших размерах кода и т. Д.
  • на сайте вызываемого абонента, мы открыли доступ кзначение в стеке (или регистр) в косвенном направлении в указатель.Теперь этот указатель, скорее всего, будет находиться в кеше, но мы все же превратили доступ к значению из одной инструкции в доступ из двух инструкций.
  • И так далее.

Предположим, что это double, а вы измените его на in double.Опять же, теперь переменная не может быть зарегистрирована в высокопроизводительном регистре с плавающей запятой.Это не только влияет на производительность , но также может изменить поведение программы!C # разрешается выполнять арифметику с плавающей точкой с точностью выше 64 бит и обычно делает это только в том случае, если числа с плавающей точкой могут быть зарегистрированы.

Это не бесплатная оптимизация.Вы должны измерить его эффективность против альтернатив.Лучше всего в первую очередь просто не создавать большие структуры, как предлагают рекомендации по проектированию.

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

в это ссылка только для чтения в c # 7.2

это означает, что вы не передаете весь объект в стек функций, как в ref , если вы передаете только ссылку на структуру

, но попытка изменить значение объекта приводит к ошибке компилятора.

И да, это позволит вам оптимизировать производительность кода, если вы используете большие структуры.

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

in был недавно введен в язык C #.

in на самом деле ref readonly.Вообще говоря, есть только один вариант использования, в котором in может быть полезен: высокопроизводительные приложения, работающие с большим количеством больших readonly struct s.

Предполагая, что у вас есть:

readonly struct VeryLarge
{
    public readonly long Value1;   
    public readonly long Value2;

    public long Compute() { }
    // etc
}

и

void Process(in VeryLarge value) { }

В этом случае структура VeryLarge будет передана по ссылке без создания защитных копий при использовании этой структуры в методе Process (например, при вызове value.Compute()), а такженеизменность структуры обеспечивается компилятором.

Обратите внимание, что передача не-только для чтения struct с модификатором in заставит компилятор создать защитную копию при вызове методов struct и доступе к свойствам в методе Processвыше, что негативно скажется на производительности!

Есть действительно хорошая запись в блоге MSDN , которую я рекомендую внимательно прочитать.

Если вы хотите получить более историческийВы можете прочитать эту дискуссию в репозитории GitHub языка C #.

В целом, большинство разработчиков сходятся во мнении, что введение in может рассматриваться как ошибка.Это довольно экзотическая языковая функция, которая может быть полезна только в случаях с высокими характеристиками.

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

Это сделано из-за подхода функционального программирования.Одним из основных принципов является то, что функция не должна иметь побочных эффектов, что означает, что она не должна изменять значения параметров и должна возвращать некоторое значение.В C # не было способа передать структуры (и тип значения) без копирования только по ссылке, что позволяет изменять значение.В Swift есть хакерский алгоритм, который копирует структуру (их коллекции - структуры BTW), пока метод начинает изменять свои значения.Люди, которые используют Swift, не все знают о копировании.Это хорошая функция c #, так как она эффективна и явно используется в памяти.Если вы посмотрите на что нового , вы увидите, что все больше и больше делается вокруг структур и массивов в стеке.И в заявлении просто необходим для этих функций.Есть ограничения, упомянутые в других ответах, но они не настолько важны для понимания того, куда движется .net.

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

Есть.При передаче struct ключевое слово in позволяет выполнить оптимизацию, когда компилятору нужно только передать указатель, без риска изменения метода методом. Последнее имеет решающее значение - оно избегает копированияоперация.На больших структурах это может изменить мир.

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