Проблема производительности IronRuby при использовании переменных - PullRequest
1 голос
/ 02 ноября 2009

Вот код очень простого средства оценки выражений, использующего IronRuby

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 не является решением для меня.

Ответы [ 2 ]

2 голосов
/ 15 декабря 2009

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

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

0 голосов
/ 05 ноября 2009

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

valuator.Evaluate (string.format ("a = {0}; b = {1}; a + b + 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)

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

...