Наскільки дорого коштує відображення .NET?


210

Я постійно чую, як погана рефлексія використовувати. Хоча я взагалі уникаю роздумів і рідко знаходжу ситуації, коли неможливо вирішити свою проблему без цього, мені було цікаво ...

Тим, хто використовував рефлексію в додатках, ви оцінювали ефективність і чи справді це так погано?


Ви також можете перевірити це питання. stackoverflow.com/questions/224232 / ...
smaclell

1
Використовуйте api на quickflect.codeplex.com. Це пришвидшить роздуми приблизно як у 500 разів для одержувачів / сетерів / викликів та інших речей. Джерело та інформація про те, як це працює, також є, якщо вам потрібно розширити їх.
Брендон Мур

3
Як ця інформація перевіряється у 2014 році? Щось змінилося за ці 4 роки?
Арнтор

1
Просте завдання присвоїти значення властивості екземпляра приблизно в 150 разів повільніше, виконуючи це з відображенням (PropertyInfo.SetValue (екземпляр, значення)), ніж з прямим кодуванням (instance.property = значення). Це в .NET 4.0
Thanasis Ioannidis

Відповіді:


130

Це є. Але це залежить від того, що ви намагаєтеся зробити.

Я використовую роздуми для динамічного завантаження збірок (плагінів), і його продуктивність "штраф" не є проблемою, оскільки операція - це те, що я роблю під час запуску програми.

Однак, якщо ви відображаєте всередині серії вкладених циклів із відображенням дзвінків на кожному, я б сказав, що вам слід переглянути свій код :)

Для операцій «за кілька разів» роздуми цілком прийнятні, і ви не помітите жодних затримок або проблем з цим. Це дуже потужний механізм, і його навіть використовує .NET, тому я не розумію, чому ви не повинні спробувати.


Я використовував роздуми, щоб отримати метод, назву класу поточного методу, щоб зареєструвати помилку в спробі лову. в основному, щоб уникнути жорсткого кодування назви функції під час помилки реєстрації. Чи потрібно хвилюватися?
Sangram Nandkhile

@Sangram nope, це нормально
Karthik AMR

@Sangram ні, якщо у вас є багато помилок, які вимагають постійного лову, що тоді має бути іншою проблемою :)
Martin Marconcini

5
@Sangram, хоча ефективність рефлексії не повинна бути проблемою у вашому випадку, схоже, ви намагаєтесь знову реалізувати те, що звичайні старі винятки забезпечують набагато більш елегантний спосіб з ящика ...
Jacek Gorgoń

152

У своїй розмові «Продуктивність повсякденних речей» Джефф Ріхтер показує, що викликати метод за допомогою рефлексії приблизно в 1000 разів повільніше, ніж називати його зазвичай.

Порада Джеффа: якщо вам потрібно викликати метод кілька разів, використовуйте роздум один раз, щоб знайти його, потім призначте його делегату , а потім викликайте делегата.


18
Я також відвідував Devscovery і погоджуюся з цими результатами для .NET 3.5. Перекомпіляція базової програми продуктивності Devscovery для .NET 4 демонструє значне поліпшення! Вартість падає в 100 разів повільніше. Використання відображення для пошуку typeof () не змінюється між .NET 3.5 та .NET 4.
John Wigger

61

Ефективність відображення буде залежати від реалізації (повторювані дзвінки повинні кешуватися, наприклад:) entity.GetType().GetProperty("PropName"). Оскільки більшість відображень, які я бачу щодня, використовуються для заповнення сутностей із зчитувачів даних або інших структур типу сховища, я вирішив орієнтувати ефективність саме на відображення, коли воно використовується для отримання або встановлення властивостей об'єктів.

Я створив тест, який, на мою думку, є справедливим, оскільки він кешує всі повторювані дзвінки і лише разів реально викликає SetValue або GetValue. Весь вихідний код для тесту на працездатність знаходиться у біт-коді за адресою: https://bitbucket.org/grenade/accessortest . Ретельний аналіз вітається і заохочується.

Я дійшов висновку, що це не практично і не забезпечує помітних поліпшень продуктивності для видалення відображення в рівні доступу до даних, який повертає менше 100 000 рядків у той час, коли реалізація відображення виконана добре.

Графік часу (у) проти кількості населених пунктів (х)

Наведений вище графік демонструє результат мого маленького орієнтиру і показує, що механізми, які перевершують відображення, роблять це помітно лише після позначки 100 000 циклів. Більшість DAL-файлів одночасно повертають кілька сотень чи, можливо, тисяч рядків, і на цих рівнях відображення спрацьовує чудово.


9
Не обов'язково. Ваша конверсія DAL може бути лише на кілька тисяч елементів, але помножити її на одночасних користувачів, які використовують вашу програму (якщо це веб-версія), і вона може скластися так само, як якщо б ви конвертували мільйон елементів. Якщо конкретний метод у 100 разів повільніше, він буде набагато повільніше на малих і великих наборах. Повільніше - повільніше.
Роберт Коритник

@RobertKoritnik Це припущення, що веб-методи на вашому сервері не є асинхронними
Kurren

@kurren асинхронність не впливає на відображення, а скоріше на серверні ресурси. Асинхронні веб-методи, звичайно, зможуть обслуговувати більше користувачів, але рефлексія все ще буде повільною. І само відображення AFAIK так чи інакше є синхронним процесом. З іншого боку, отримання даних буде єдиною частиною, яка чудово зіграє з асинхронним дизайном.
Роберт Коритник

3
Який метод Гіпер на графіку? Чим він відрізняється від рефлектора?
Легенда про Брайана

Я повинен був посилатися цей @LoneCoder: codeproject.com/Articles/18450 / ... по stackoverflow.com/users/23354/marc-gravell
гранати


12

Моїм найбільш відповідним досвідом було написання коду для порівняння будь-яких двох об'єктів даних одного типу у великій об'єктній моделі властивості. Зробив це, спробував, побіг, як собака, очевидно.

Я зневірився, а потім протягом ночі зрозумів, що без зміни логіки я можу використовувати той же алгоритм для автоматичного генерування методів для порівняння, але статичного доступу до властивостей. Для адаптації коду для цієї мети не знадобилося часу, і я мав можливість провести глибоке порівняння об'єктів зі статичним кодом, яке можна було оновлювати одним натисканням кнопки щоразу, коли модель об'єкта змінювалася.

Моя думка: у розмовах з колегами, оскільки я вже кілька разів вказував, що їх використання відображення може бути для автоматичного створення коду для компіляції, а не для виконання операцій виконання, і це часто варто враховувати.


Враховуючи, що Visual Studio має таку чудову підтримку шаблонів, це практичний спосіб використання генерації коду
Себастьян

12

Не масово. У мене ніколи не було проблем з цим у розробці настільних комп’ютерів, якщо, як стверджує Мартін, ви використовуєте його в нерозумному місці. Я чув, що багато людей мають абсолютно ірраціональні побоювання щодо її ефективності в розробці настільних ПК.

Хоча в Компактній Рамі (в якій я зазвичай є), це майже анафема, і її слід уникати, як чуми, у більшості випадків. Я все ще можу піти з його використання нечасто, але я повинен бути дуже обережним з його застосуванням, що набагато менш цікаво. :(


5
+1 для того, щоб навчити мене новому слову: анафема. Також для згадки про ірраціональні страхи. Я боюся програмістів, які бояться ірраціонально - це показує, що вони насправді не знають, що роблять, і просто ґрунтуються на тому, що роблять на тому, що говорять їм інші люди. кашель вантажний культ кашель
bsneeze

1
Ahhhh Cargo Cult. Зараз є прекрасний приклад допитливої ​​поведінки людини.
Дивовижна

10

Це досить погано, що вам доведеться турбуватися навіть про роздуми, зроблені внутрішньо бібліотеками .NET для критичного продуктивного коду.

Наступний приклад є застарілим - істинним на той час (2008), але давно зафіксованим у новіших версіях CLR. Рефлексія взагалі все ще дещо дорога річ!

Справа в суті: Ви ніколи не повинні використовувати члена, оголошеного як "Object", у операторі lock (C #) / SyncLock (VB.NET) у високопродуктивному коді. Чому? Оскільки CLR не може заблокувати тип значення, це означає, що він повинен зробити перевірку типу відображення під час виконання, щоб побачити, чи є ваш Об’єкт насправді типом значення замість еталонного типу.


13
Справедливості, перевірка типу відображення швидка.
Джиммі

1
Для такого "критичного коду щодо продуктивності" ви дійсно повинні використовувати .NET для початку?
Seph

1
@Seph: Динамічні / відбиваючі частини .NET, ні. Але звичайна C # /. NET, чому б і ні? Прискорення C ++ проти C # є граничними на рівні додатків (C ++ все ще на кілька відсотків швидше в інтенсивних математичних процедурах). І я здогадуюсь, що ви не пропонуєте збірку ...
DeepSpace101

Тип коробкового значення (тобто об'єкт) можна заблокувати. @BryceWagner правильний.
Птиця

1
Якщо бути справедливим (для мене), точніше сказати, що відповідь - "застаріла", а не "проста дурниця". Мої зауваження щодо поведінки lock (obj) БИЛО точні на час їх написання, але що поведінка CLR, що стосується конкретної реалізації, давно минула.
McKenzieG1

5

Як і у всіх випадках програмування, ви повинні збалансувати вартість продуктивності та отримати будь-яку вигоду. Рефлексія - це неоціненний інструмент при обережному використанні. Я створив бібліотеку відображення O / R в C #, яка використовувала відображення для прив'язки. Це спрацювало фантастично добре. Більшість кодів відображення було виконано лише один раз, тому будь-яке звернення до продуктивності було зовсім невеликим, але переваги були великими. Якби я писав новий алгоритм сортування, що не вдається, я б, мабуть, не використовував відображення, оскільки він, мабуть, погано масштабується.

Я вдячний, що тут я точно не відповів на ваше запитання. Моя думка, це насправді не має значення. Використовуйте рефлексію, де це доречно. Це просто ще одна мовна функція, яку потрібно навчитись як і коли користуватися.


3

Відображення може мати помітний вплив на продуктивність, якщо використовувати його для частого створення об’єктів. Я розробив додаток на базі Composite UI Application Block, який сильно покладається на роздуми. Була помітна деградація продуктивності, пов'язана зі створенням об'єктів за допомогою відображення.

Однак у більшості випадків немає проблем із використанням відображення. Якщо вам потрібно лише оглянути деяку збірку, я рекомендую Mono.Cecil, який дуже легкий і швидкий


3

Роздуми є дорогими через багато перевірок, які час виконання повинен робити, коли ви робите запит на метод, який відповідає списку параметрів. Десь глибоко всередині існує код, який перетинає всі методи для типу, перевіряє його видимість, перевіряє тип повернення, а також перевіряє тип кожного параметра. Весь цей матеріал коштує часу.

При внутрішньому виконанні цього методу існує деякий код, який робить такі речі, як перевірка, ви передали сумісний список параметрів перед виконанням фактичного цільового методу.

Якщо це можливо, завжди рекомендується кешувати ручку методу, якщо ви будете постійно використовувати його в майбутньому. Як і всі хороші поради щодо програмування, часто має сенс уникати повторень. У цьому випадку було б марно постійно шукати метод за певними параметрами, а потім виконувати його щоразу.

Огляньте джерело і подивіться, що робиться.


3

Як і у всьому, справа в оцінці ситуації. У DotNetNuke є досить основний компонент, який називається FillObjectвідображенням для заселення об'єктів з даних.

Це досить поширений сценарій, і є стаття про MSDN, що використовує Reflection для прив’язки бізнес-об'єктів до ASP.NET Form Controls, яка охоплює проблеми продуктивності.

Ефективність убік, одне, що мені не подобається у використанні рефлексії у конкретному сценарії, це те, що воно, як правило, знижує здатність зрозуміти код на швидкий погляд, що для мене не здається вартим зусиль, коли ви вважаєте, що також втрачаєте компіляцію безпека часу на відміну від сильно набраних наборів даних або чогось типу LINQ для SQL .


2

Роздум не різко уповільнює ефективність вашої програми. Ви можете зробити певні речі швидше, не використовуючи рефлексію, але якщо Роздум - це найпростіший спосіб досягти певної функціональності, тоді використовуйте це. Ви завжди можете рефактор, який ви кодуєте далеко від Reflection, якщо це стає проблемою Perf.


1

Я думаю, ви виявите, що відповідь є, це залежить. Це не велика справа, якщо ви хочете помістити це у свою програму списку завдань. Велика справа, якщо ви хочете помістити його в бібліотеку наполегливості Facebook.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.