2009-11-02 7 views
1

Вот код очень простого выражение оценщика с использованием IronRubyIronRuby проблема производительность при использовании переменных

public class BasicRubyExpressionEvaluator 
{ 
    ScriptEngine engine; 
    ScriptScope scope; 
    public Exception LastException 
    { 
     get; set; 
    } 
    private static readonly Dictionary<string, ScriptSource> parserCache = new Dictionary<string, ScriptSource>(); 
    public BasicRubyExpressionEvaluator() 
    { 
     engine = Ruby.CreateEngine(); 
     scope = engine.CreateScope(); 

    } 

    public object Evaluate(string expression, DataRow context) 
    { 
     ScriptSource source; 
     parserCache.TryGetValue(expression, out source); 
     if (source == null) 
     { 
      source = engine.CreateScriptSourceFromString(expression, SourceCodeKind.SingleStatement); 
      parserCache.Add(expression, source); 
     } 

     var result = source.Execute(scope); 
     return result; 
    } 
    public void SetVariable(string variableName, object value) 
    { 
     scope.SetVariable(variableName, value); 
    } 
} 

и здесь проблема.

var evaluator = new BasicRubyExpressionEvaluator(); 
evaluator.SetVariable("a", 10); 
evaluator.SetVariable("b", 1); 
evaluator.Evaluate("a+b+2", null); 

против

var evaluator = new BasicRubyExpressionEvaluator(); 
evaluator.Evaluate("10+1+2", null); 

Первый Является 25 раз медленнее, чем второй. Какие-либо предложения? String.Replace для меня не является решением.

+0

также можно кэшировать CompiledCode вместо ScriptSource –

ответ

2

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

Кроме того, в вашем коде хостинга, как вы относитесь к ScriptScopes в словаре? Я бы держал на CompiledCode (результат engine.CreateScriptSourceFromString (...). Компиляция()) вместо этого, поскольку это поможет намного больше в повторных запусках.

+0

да Компиляция() резко повышает производительность. –

0

вы можете, конечно, первым построить строку вроде

evaluator.Evaluate (string.Format ("а = {0}; б = {1}, а + Ь + 2", 10, 1))

Или вы можете сделать его методу

если вместо вашего сценария вы возвращаете метод, то вы должны быть в состоянии использовать его как обычный объект C# Func.

var script = @" 

def self.addition(a, b) 
    a + b + 2 
end 
" 

engine.ExecuteScript(script); 
var = func = scope.GetVariable<Func<object,object,object>>("addition");  
func(10,1) 

Это, вероятно, не рабочий фрагмент, но он показывает общую идею.