Почему рефлексия плохо работает в .NET? - PullRequest
5 голосов
/ 22 июля 2009

Мне интересно узнать технические причины: почему рефлексия плохо работает в .NET?

Ответы [ 7 ]

16 голосов
/ 22 июля 2009

отражение не работает хорошо

Это очень загруженное утверждение. «Выполнить хорошо» является относительным. По сравнению со статическим кодом отражающие вызовы не выполняют так же хорошо, как . Однако почти во всех случаях отражение в .NET очень быстро . Я не могу преуменьшить это достаточно. Отражение получило плохую репутацию в дни .NET 1.x и, возможно, на других языках, но отражение в .NET 2.0+ невероятно быстро .

В 99% случаев «слишком медленное отражение» не имеет значения. Я сомневаюсь, что вам понадобится измерить влияние производительности отражательного вызова на статический.

5 голосов
/ 22 июля 2009

Простое заявление о том, что «Reflection» работает медленно, превращает адскую массу функциональных возможностей в очень широкое одеяло. Отражение в .NET состоит из нескольких классов, каждый с разным уровнем «производительности». Например, использование оператора typeof() на самом деле является формой отражения ... он запрашивает метаданные CLR для типа. Однако typeof() выполняется очень быстро (в почти свободное время). Использование других «отражений», связанных с типом, таких как оператор is, оператор sizeof() и т. Д., Также почти бесплатны (в основном они работают так, как будто они были статические коды.)

Отражение, используемое для извлечения информации о типе, хотя и медленнее, чем typeof(), также очень и очень быстро, учитывая количество обхода указателя и проверку метаданных. Зондирование метаданных является довольно распространенной практикой для кода .NET, особенно когда речь идет о работе с пользовательскими атрибутами.

Большая проблема производительности в отношении рефлексии связана с вызовом. Доступ к информации о типе и чтение метаданных довольно легки. В тот момент, когда вы задействуете динамический вызов свойств, индексаторов, методов или динамически создаете новые типы с помощью отражения, вы получаете прирост производительности на порядки.

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

Добавление:

Немного запоздалая мысль, но если вам требуется высокая степень динамического вызова членов типа с поздней привязкой, вам следует взглянуть на упрощенную генерацию кода. Используя пространство имен System.Reflection.Emit, вы можете использовать такие утилиты, как DynamicMethod, для генерации облегченного кода во время выполнения, который может выполнять вызовы с ранней привязкой. Кэширование этого сгенерированного кода снижает первоначальные затраты на его генерацию, позволяя вам получить выгоду от вызовов с поздней связью и производительностью с ранней связью.

4 голосов
/ 22 июля 2009

Потрясающая статья об этом на MSDN: Уклонение от общих ошибок производительности для создания быстрых приложений . По сути, это вопрос позднего и раннего связывания. То есть, что может быть решено во время компиляции и что должно быть решено во время выполнения. Из этой статьи ...

Последние случаи MethodBase.Invoke, DynamicMethod через Invoke, Type.InvokeMember и вызовы делегатов с поздней привязкой делегаты через Delegate.DynamicInvoke). Все эти методы идут с значительно более отрицательный последствия для производительности, чем ранние случаи. Даже в лучшем случай, они, как правило, порядка величина медленнее самой медленной ранний случай.

Он ломает наши многочисленные тесты производительности различных способов делать ранние и поздние связанные вызовы. Стоит прочитать.

2 голосов
/ 22 июля 2009

Отражение работает хорошо, просто делает намного больше, чем статический код.

Скажем, у вас есть фрагмент кода:

typeof(SomeClass).GetMethod("SomeStaticMethod").
Invoke(null, new object[] { 1, 2, 3 });

Это то же самое, что и это:

SomeClass.SomeStaticMethod(1, 2, 3);

Но должно быть очевидно, что у первого гораздо больше работы. Он должен получить информацию о типе, просмотреть ее, чтобы увидеть, есть ли метод SomeStaticMethod, проверить, какой это метод, вызвать метод в экземпляре или нет, если он статический, и передать массив объектов в качестве параметров, упаковав / распаковав целые числа. и в этом случае.

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

1 голос
/ 22 июля 2009

Отражение включает переход к метаданным для преобразования имен в токены, затем он использует эти токены для поиска и извлечения нужных данных (например, токен метода используется для получения информации о методе, параметрах ... и т.д.).

Этот процесс дорогой по двум причинам. 1- происходит много поисков 2- Касание страниц, которые обычно не затрагиваются (холодные страницы), которые содержат таблицы метаданных.

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

1 голос
/ 22 июля 2009

Поскольку он включает поиск строк (имен типов и элементов) во время выполнения, а также дополнительную упаковку / распаковку для типов значений.

0 голосов
/ 22 июля 2009

Отражение хорошо работает в .NET - для того, что он делает.

Однако рефлексия, так как это анализ уже скомпилированных типов во время выполнения, требует довольно много накладных расходов. В общем, выполнение таких операций, как поиск строк в статической информации о типах, а также обход метаданных класса и т. Д., Займет некоторое время.

Это не значит, что он действительно медленный - он просто НАМНОГО медленнее, чем полностью скомпилированный, прямой вызов методов и поиск. Так и должно быть - но я действительно думаю об этом больше, так как скомпилированный код работает быстрее, чем динамический поиск информации в любой системе.

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