MCP

четверг, 3 сентября 2009 г.

Немножко про Reflection

Недавно проверял скорость работы Reflection в плане того, насколько оно медленное. Расписывать все случаи не буду, также не буду утверждать что все замеры корректные, просто немного данных для информации, чтобы вы знали, что ожидать от Reflection:

  • Вызов метода через рефлекшен отличается в зависимости от того, является ли метод public или private
  • Для public вызов метода где-то в 100-150 (!) раз медленнее, чем обычный вызов
  • Для private вызов медленнее где-то раз в 400-500 (!). Выводы делайте сами.
  • Время на вызовы GetMethodInfo относительно невелико, при этом, похоже это всё кешируется. Так что особо оптимизировать вызовы тут смысла нет
  • Если вы точно знаете сигнатуру метода, который берёте через рефлекшен (в качестве варианта, пнуть какой-нибудь приватный метод, или при использовании какого-либо варианта плагинов), то можно воспользоваться Delegate.CreateDelegate с указанием нужного типа, получить правильный делегат и его вызов будет таким же быстрым (возможно даже чуть быстрее, есть подозрение на использование call вместо callvirt), как и прямой вызов
  • Если точно не знаете сигнатуру, то можно использовать Delegate.DynamicInvoke но производительность будет примерно такая же, как и у чистого рефлекшена
  • Если хотите использовать Expression для генерации, в частности LambdaExpression то совет тот же. Используйте чётко типизированный .Compile() и получите почти идеальную производительность (где-то 1.5, но компиляция не очень шустрая). С учётом того, что экспрешены — достаточно могучий механизм, подобное стоит использовать. Есть интересные задачи, где они могут сильно облегчить жизнь, или даже сделать что-то особенное.

Ну вот, в общем и всё. Пока для меня остаётся открытым вопрос: "Как использовать преимущества делегатов без возможности указания нужного типа напрямую", чтобы получить хорошую производительность для рефлешкена. Смотрю в сторону DynamicMethod, но это уж больно серьёзная артиллерия (хотя производительность замечательная).