Деревья выражений и IL.Emit для специализации кода времени выполнения

Недавно я узнал, что можно генерировать код C# во время выполнения, и я хотел бы использовать эту функцию. У меня есть код, который выполняет некоторые очень простые геометрические вычисления, такие как вычисление пересечений линии и плоскости, и я думаю, что мог бы получить некоторые преимущества в производительности, создав специализированный код для некоторых методов, потому что многие вычисления выполняются для одной и той же плоскости или одной и той же линии. и снова. Специализируя код, вычисляющий пересечения, я думаю, что смогу получить некоторые преимущества в производительности.

Проблема в том, что я не знаю, с чего начать. Прочитав несколько сообщений в блогах и просмотрев документацию MSDN, я обнаружил две возможные стратегии генерации кода во время выполнения: деревья выражений и IL.Emit. Использование деревьев выражений кажется намного проще, потому что нет необходимости изучать что-либо об OpCodes и различных других тонкостях, связанных с MSIL, но я не уверен, что деревья выражений так же быстры, как MSIL, сгенерированные вручную. Итак, есть ли какие-либо предложения о том, какой метод мне следует использовать?


person David K.    schedule 15.01.2012    source источник


Ответы (2)


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

Я настоятельно рекомендую приобрести инструмент под названием ILSpy, который выполняет обратную компиляцию сборок CLR. С этим вы можете посмотреть на код, который фактически обходит деревья выражений и фактически генерирует IL.

Наконец, предостережение. Я использовал деревья выражений в синтаксическом анализаторе языка, где вызовы функций связаны с правилами грамматики, которые компилируются из файла во время выполнения. Скомпилировано является ключевым здесь. Для многих проблем, с которыми я сталкивался, когда то, чего вы хотите достичь, известно во время компиляции, вы не получите большой производительности за счет генерации кода во время выполнения. Некоторые оптимизации CLR JIT также могут быть недоступны для динамического кода. Это только мнение из моей практики, и ваш домен был бы другим, но если производительность критична, я бы предпочел смотреть на нативный код, высокооптимизированные библиотеки. Некоторая работа, которую я проделал, была бы очень медленной, если бы я не использовал LAPACK/MKL. Но это всего лишь совет, о котором не просили, так что принимайте его с недоверием.

person kkm    schedule 15.01.2012
comment
Я бы добавил, что написание собственного IL чревато возможностью пропустить оптимизации, которые может найти компилятор C#. Вы можете захотеть создать фактический C# и использовать компилятор C# для создания результирующих сборок: msdn.microsoft.com/en-us/library/ - person Chris Shain; 15.01.2012
comment
@ChrisShain, к сожалению, компилятор C # не выполняет никаких интересных возможных оптимизаций. Даже C++/CLI почему-то делает гораздо больше. Вот почему я предпочитаю генерировать код самостоятельно, минуя ограниченные возможности оптимизации C#. Есть вещи, которые очень легко реализовать, но которых нет в C# — правильное распространение констант, специализация константных аргументов (с встраиванием), анализ областей и устранение распределения, развертывание цикла, объединение переменных, подъем инварианта цикла и т. д. - person SK-logic; 18.01.2012
comment
Причина, по которой компилятор C# не выполняет эти оптимизации, заключается в том, что эта ответственность лежит на JIT-компиляторе. Причина здесь в том, что перенос оптимизаций, таких как развертывание циклов, в JIT-компилятор, позволяет применять их ко всем языкам .NET. Конечно, компилятор JIT выполняет развертывание циклов, встраивание и многое другое. - person Pieter van Ginkel; 28.10.2013
comment
Вы, ребята, возможно, захотите увидеть оптимизирован. - person nawfal; 18.12.2013

Если бы я был в вашей ситуации, я бы попробовал альтернативы с высокого уровня на низкий уровень, увеличив «необходимое время и усилия» и уменьшив порядок повторного использования, и я бы остановился, как только производительность будет достаточно хороша на данный момент, т.е.:

  • во-первых, я бы проверил, имеет ли Math.NET, LAPACK или какая-либо подобная числовая библиотека аналогичную функциональность, или я могу адаптировать/расширить код для своих нужд;

  • во-вторых, я бы попробовал деревья выражений;

  • в-третьих, я бы проверил Roslyn Project (хотя это и предварительная версия);

  • в-четвертых, я бы подумал о написании обычных подпрограмм с небезопасным кодом на C;

  • [в-пятых, я бы подумал о том, чтобы бросить курить и начать новую карьеру в другой профессии :) ],

  • и только если ничего из этого не сработает, я буду настолько безнадежен, что попытаюсь запустить IL во время выполнения.

Но, возможно, я предвзято отношусь к низкоуровневым подходам; ваш опыт, опыт и точка зрения могут отличаться.

person Ali Ferhat    schedule 15.01.2012
comment
Испускание il — это большая проблема в ###, но вы многое узнаете о внутренней работе clr!!! - person Peter; 14.07.2012