-
Notifications
You must be signed in to change notification settings - Fork 0
Быстродействие
Быстродействие может стать краеугольным камнем при использовании какого-либо компонента. Все хотят чтоб их продукты работали быстро, и уж точно не хотелось бы получить значительную деградацию производительности при выполнении простого метода из-за наличия дополнительной прослойки в виде динамического прокси объекта. При разработке библиотеки выполнялось тщательное профилирование, по результатам которого проводились разного уровня оптимизации - от использования деревьев выражений для вызова методов (вместо рефлексии) до многоуровневого кеширования различных признаков и информации о типах с использованием шаблона Memoizer. Однако, не смотря на это, некоторые перфоманс деградации все таки имеют место быть, поэтому повсеместное бездумное применение данной библиотеки не рекомендуется.
- Используйте аспекты на методы бизнес-логики, которые погрязли в копипасте из сквозной функциональности (кеширование, проверка прав, обработка исключений). Если метод делает какие-то тяжелые действия, например сериализует объекты, получает данные из базы, читает или пишет файлы, то применение аспектов абсолютно никак не снизит быстродействие.
- Не используйте аспекты на методы, для которых скорость работы - это приоритетная задача. Если задача метода произвести преобразование картинки из одного формата в другой и он вызывается миллионы раз, то лучше не замедлять его работу введением дополнительных прослоек вызовов
Профилирование библиотеки выполняется посредством механизма микробенчмарков и специального фреймворка для этих целей - BenchmarkDotNet. Результаты представлены ниже
Method | Mean | Error | StdDev |
---|---|---|---|
Вызов метода напрямую | 1.902 ns | 0.0755 ns | 0.0927 ns |
Вызов метода объекта через DispatchProxy | 575.124 ns | 11.2527 ns | 14.2311 ns |
Вызов метода скомпонованного объекта | 1,402.062 ns | 27.4180 ns | 35.6512 ns |
Вызов метода через рефлексию | 344.422 ns | 6.7755 ns | 6.6544 ns |
Окружение
BenchmarkDotNet=v0.10.12, OS=macOS 10.13.3 (17D47) [Darwin 17.4.0]
Intel Core i5-7360U CPU 2.30GHz (Kaby Lake), 1 CPU, 4 logical cores and 2 physical cores
.NET Core SDK=2.1.4
[Host] : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT
Core : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT
Легенда
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
1 ns : 1 Nanosecond (0.000000001 sec)
Как видно, вызов скомпонованного метода представленного 3м в списке, всего в 4 раза медленнее вызова этого же метода через рефлексию (MethodInfo.Invoke
) и в менее чем 3 раза медленее, чем обернутый тип в динамический прокси, а точнее его реализации в CoreFX. При том речь тут идет о наносекундах. Для сравнения, бенчмарк на сериализацию простого объекта из двух строковых и одного целочисленного поля через бинарную сериализацию (BinaryFormatter
) дает следующие результаты.
Method | Mean | Error | StdDev |
---|---|---|---|
Сериализация | 17.00 us | 0.3384 us | 0.6189 us |
Десериализация | 17.00 us | 0.3374 us | 0.7887 us |
1 us - 1 Микросекунда (0.000001 sec).
То есть 17 us - 17000 ns. На основе этих цифр можно сделать вывод, что сериализация простого объекта из трех свойств почти в 13 раз медленнее, чем вызов метода объекта, скомпонованного с декларативным аспектом внутри динамического прокси. Попрофилировать самому можно запустив этот проект.