Страницы

Поиск по вопросам

понедельник, 24 февраля 2020 г.

Скорость работы dynamic в C#

#c_sharp #оптимизация #clr


Смотрю курсы по C# proffesional от ITVDN. Там пример, первый раз обращаются к полю
dynamic, которое раннее приравнено к ссылке на объект, и показывают, что первое обращение
к такому полю занимает 2 миллиона тиков. Я повторяю это на своем компьютере, но у меня
всего 2 тысячи тиков. Примерно в 10 раз больше, чем следующие обращения к dynamic.
Соль то в том, что dynamic запоминает объект, но в первый раз он ничего о нем не знает
и поэтому занимает больше времени. Но 2 тысячи и 2 миллиона для одинаковых функций
- очень большая разница. Может курс устарел и разработчики C# оптимизировали dynamic?
Код:

MyClass c = new MyClass();
dynamic d = c;
long start, end;

while (true)
{
    QueryPerformanceCounter(out start);
    d.m();
    QueryPerformanceCounter(out end);
    Console.WriteLine((end - start) + '\n');
} 

    


Ответы

Ответ 1



На вопрос о разнице в количестве тиков отвечать не буду, потому как неизвестны ни способ измерения, ни конфигурации вашего и автора курса компьютеров, ни версии .NET. Вместо этого отвечу, почему первый вызов метода работает медленнее. Авось кому пригодится. Дополнения к посту приветствуются. Для каждого выражения (операции), использующего объект типа dynamic, компилятор генерирует специальный объект под названием dynamic call site, который представляет это выражение (операцию). После компиляции приведенного в вопросе кода получается примерно следующее (код с измерением опустил): static DynamicCallSite dCallSite; ... MyClass c = new MyClass(); dynamic d = c; while (true) { if (dCallSite == null) { dCallSite = new DynamicCallSite(); } dCallSite.DoInvocation("m", d); } При этом объект dynamic call site генерируется только один раз для каждого выражения. Это первая монетка в копилку "почему первый вызов работает медленнее". Дальше DLR проверяет типа объекта d, обнаруживает, что это C# объект, и вызывает С# компилятор, который, используя метаданные, генерирует expression tree для данного выражения. Expression tree возвращается обратно DLR, компилируется, получившийся делегат вызывается и кэшируется. Т.е. если DLR в дальнейшем встретит такое же выражения для объекта такого же типа, будет вызван закэшированный делегат. Это вторая монетка в копилку "почему первый вызов работает медленнее". Во время второго вызова у нас уже есть dynamic call site, так что DLR просто проверяет тип объекта, достает из кэша скомпилированный делегат и выполняет его.

Комментариев нет:

Отправить комментарий