У меня есть метод хеширования, операции которого зависят от ввода функции. Профилирование программы показало, что слишком много времени тратится на оценку этого метода хеширования. Я хочу попробовать превратить его в дерево выражений, чтобы проверки внутреннего цикла можно было выполнить один раз. Надеюсь, это будет быстрее, но я в любом случае узнаю о деревьях выражений.
Вот упрощенная версия функции (я отменил некоторые очевидные оптимизации для примера и убрал любую проверку ввода):
Private Function Checksum(ByVal inputValues As IEnumerable(Of UInt32),
ByVal declarations As IEnumerable(Of String),
ByVal statements As IEnumerable(Of String)) As UInt32
Dim variables = New Dictionary(Of Char, UInt32)
For Each declaration In declarations
'parse declaration (eg. "X=52")'
variables(declaration(0)) = UInt32.Parse(declaration.Substring(2))
Next declaration
For Each value In inputValues
'"I"nput'
variables("I"c) = value
For Each statement In statements
'parse statement (eg. "X=Y+Z")'
Dim varResult = statement(0)
Dim valueLeft = variables(statement(2))
Dim operand = statement(3)
Dim valueRight = variables(statement(4))
'execute statement'
Dim valueResult As UInt32
Select Case operand
Case "+"c : valueResult = valueLeft + valueRight
Case "-"c : valueResult = valueLeft - valueRight
Case "*"c : valueResult = valueLeft * valueRight
Case "&"c : valueResult = valueLeft And valueRight
Case "|"c : valueResult = valueLeft Or valueRight
Case "^"c : valueResult = valueLeft Xor valueRight
End Select
variables(varResult) = valueResult
Next statement
Next value
'"O"utput'
Return variables("O"c)
End Function
Я хочу создать функцию, которая принимает объявления и операторы и выводит специализированное дерево выражений, представляющее функцию, которая принимает IEnumerable из UInt32 и возвращает UInt32.
Следовать за:
Мне это удалось, и ускорение было смехотворным (на порядок). Основное, чему мне пришлось научиться, где:
- Используйте Expression.Lambda и Expression.Compile, чтобы получить делегат, который вы действительно можете использовать.
- Фабричный метод Expression.Block имеет параметр «переменные», который вы (по существу) используете для объявления локальных переменных. Точно так же Expression.lambda имеет «параметры».
- Если вы вызываете Expression.Parameter дважды, вы имеете дело с двумя разными переменными (даже если их имена совпадают)! Сохраните результат для последующего использования. То же самое с этикетками и т.д.
- Результатом BlockExpression является последнее выражение в блоке.