Динамическое ключевое слово C # - штраф за время выполнения? - PullRequest
16 голосов
/ 24 сентября 2010

Означает ли определение экземпляра как динамического в C #:

  1. Компилятор не выполняет проверку типов во время компиляции, но проверка во время выполнения происходит, как это всегда происходит для всех экземпляров.

  2. Компилятор не выполняет проверку типов во время компиляции, но выполняется во время выполнения, в отличие от любых других нединамических экземпляров.

  3. То же, что 2, и это приводит к снижению производительности (тривиально? Потенциально значимо?).

Ответы [ 5 ]

39 голосов
/ 24 сентября 2010

Вопрос очень запутанный.

Означает ли определение экземпляра как динамического в C #:

Под "определением экземпляра" вы подразумеваете "объявление переменной"?

Компилятор не выполняет проверку типов во время компиляции, но проверка во время выполнения происходит так же, как и всегда для всех экземпляров.

Что вы подразумеваете под "проверкой во время выполнения, как это всегда происходит"? Какую проверку во время выполнения вы имели в виду? Вы думаете о проверке, выполненной IL-верификатором , или вы думаете о проверках типа во время выполнения, вызванных приведениями, или как?

Возможно, было бы лучше просто объяснить, что делает "динамический".

Прежде всего, динамический с точки зрения компилятора a типа . С точки зрения CLR , не существует такой вещи, как dynamic ; к тому времени, когда код фактически выполняется, все экземпляры «dynamic» были заменены на «object» в сгенерированном коде.

Компилятор обрабатывает выражения типа dynamic точно как выражения типа object , за исключением того, что все операции над значением этого выражения анализируются, компилируются и выполняются во время выполнения на основе типа времени выполнения экземпляра. Цель состоит в том, чтобы выполняемый код имел ту же семантику , как если бы компилятор знал типы времени выполнения во время компиляции.

Ваш вопрос, кажется, о производительности.

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

Однако давайте рассмотрим влияние некоторых операций на производительность на абстрактном уровне. Предположим, у вас есть:

int x = 123;
int y = 456;
int z = x + y;

На большинство аппаратных средств добавление двух целых чисел занимает около одной миллиардной доли секунды.

Что произойдет, если мы сделаем его динамичным?

dynamic x = 123;
dynamic y = 456;
dynamic z = x + y;

Теперь, что это делает во время выполнения? Это блоки 123 и 456 в объекты, которые выделяют память в куче и делают несколько копий.

Затем он запускает DLR и спрашивает DLR "был ли этот кодовый сайт скомпилирован один раз с типами для x и y, являющимися int и int?"

Ответ в этом случае - нет. Затем DLR запускает специальную версию компилятора C #, которая анализирует выражение сложения, выполняет разрешение перегрузки и выплевывает дерево выражений , описывающее лямбду, которая складывает два целых числа. Затем DLR компилирует эту лямбду в динамически сгенерированный IL, который затем jit компилятор выполняет. Затем DLR кэширует это скомпилированное состояние, так что секунда раз, когда вы спрашиваете, компилятору не нужно делать всю эту работу снова.

Это займет дольше , чем наносекунда. Это может занять много тысяч наносекунд.

Это отвечает на ваши вопросы? Я не совсем понимаю, о чем вы здесь спрашиваете, но я делаю лучшее предположение.

7 голосов
/ 24 сентября 2010

Насколько я знаю, ответ 3.

Вы можете сделать это:

dynamic x = GetMysteriousObject();
x.DoLaundry();

Поскольку компилятор не проверяет тип на x, он скомпилирует этокод, предполагается, что вы знаете, что делаете.

Но это означает, что должна выполняться дополнительная проверка во время выполнения, а именно: проверка типа x, проверка наличия DoLaundryметод, не принимающий аргументов и выполняющий его.

Другими словами, приведенный выше код выглядит как вроде , как это делается (я не говорю, что это то же самое, просто рисую сравнение):1015 *

object x = GetMysteriousObject();

MethodInfo doLaundry = x.GetType().GetMethod(
    "DoLaundry",
    BindingFlags.Instance | BindingFlags.Public
);

doLaundry.Invoke(x, null);

Это определенно нетривиально, хотя это не значит, что вы сможете увидеть проблему с производительностью невооруженным глазом.

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

Не держи меня к этому, хотя.У меня не так много опыта с dynamic;это просто, как я понимаю, это работает.

2 голосов
/ 24 сентября 2010

Ну, переменная статически типизирована, чтобы иметь тип dynamic, но, кроме того, насколько я знаю, компилятор не выполняет никакой проверки.

Связывание типов выполняется во время выполнения, и да, есть штраф, но если dynamic - единственный вариант, то что с того. Если вы можете решить проблему, используя статическую типизацию, сделайте это. При этом DLR вызывает кэширование сайтов, что означает, что некоторые накладные расходы уменьшаются, так как в некоторых случаях сантехника может быть повторно использована.

2 голосов
/ 24 сентября 2010

Объявление переменной как dynamic аналогично объявлению ее как object .Dynamic просто получает другой флаг, указывающий, что разрешение элемента откладывается до времени выполнения .

С точки зрения снижения производительности - это зависит от того, что является основным объектом.В этом весь смысл динамических объектов, верно?Базовый объект может быть объектом Ruby или Python или объектом C #.DLR выяснит во время выполнения, как разрешить вызовы членов для этого объекта, и этот метод разрешения определит снижение производительности.

Сказав это - определенно есть снижение производительности.

Вот почему мы не просто начнем использовать повсеместно динамические объекты.

0 голосов
/ 24 сентября 2010

Насколько я понимаю, dynamic это только обходит проверку времени компиляции. разрешение типа происходит во время выполнения, как и для всех типов. так что я не думаю, что есть какие-либо потери производительности, связанные с этим.

...