Я собираюсь создать веб-сервис, который выполняет большое количество заданных вручную вычислений как можно быстрее и изучает использование DLR.
Извините, если это долго, но не стесняйтесьчтобы просмотреть общую суть.
Я использую библиотеку IronPython, поскольку она позволяет очень легко определять вычисления.Мой рабочий ноутбук дает производительность около 400 000 вычислений в секунду, выполняя следующие действия:
ScriptEngine py = Python.CreateEngine();
ScriptScope pys = py.CreateScope();
ScriptSource src = py.CreateScriptSourceFromString(@"
def result():
res = [None]*1000000
for i in range(0, 1000000):
res[i] = b.GetValue() + 1
return res
result()
");
CompiledCode compiled = src.Compile();
pys.SetVariable("b", new DynamicValue());
long start = DateTime.Now.Ticks;
var res = compiled.Execute(pys);
long end = DateTime.Now.Ticks;
Console.WriteLine("...Finished. Sample data:");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(res[i]);
}
Console.WriteLine("Took " + (end - start) / 10000 + "ms to run 1000000 times.");
Где DynamicValue - это класс, который возвращает случайные числа из предварительно созданного массива (сеяние и сборка во время выполнения).
Когда я создаю класс DLR для того же, я получаю гораздо более высокую производительность (~ 10 000 000 вычислений в секунду).Класс выглядит следующим образом:
class DynamicCalc : IDynamicMetaObjectProvider
{
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
{
return new DynamicCalcMetaObject(parameter, this);
}
private class DynamicCalcMetaObject : DynamicMetaObject
{
internal DynamicCalcMetaObject(Expression parameter, DynamicCalc value) : base(parameter, BindingRestrictions.Empty, value) { }
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
Expression Add = Expression.Convert(Expression.Add(args[0].Expression, args[1].Expression), typeof(System.Object));
DynamicMetaObject methodInfo = new DynamicMetaObject(Expression.Block(Add), BindingRestrictions.GetTypeRestriction(Expression, LimitType));
return methodInfo;
}
}
}
и вызывается / тестируется таким же образом, выполняя следующие действия:
dynamic obj = new DynamicCalc();
long t1 = DateTime.Now.Ticks;
for (int i = 0; i < 10000000; i++)
{
results[i] = obj.Add(ar1[i], ar2[i]);
}
long t2 = DateTime.Now.Ticks;
Где ar1 и ar2 - предварительно созданные массивы, заполненные во время выполненияслучайных чисел.
Скорость в этом случае велика, но не так просто определить расчет.По сути, я бы хотел создать свой собственный лексер и парсер, тогда как у IronPython уже есть все, что мне нужно.
Я бы подумал, что смогу добиться гораздо большей производительности от IronPython, поскольку он реализован поверхDLR, и я мог бы сделать лучше, чем то, что получаю.
Мой пример лучше всего использует движок IronPython?Можно ли из этого добиться значительно лучшей производительности?
(Edit) То же, что и в первом примере, но с циклом в C #, установкой переменных и вызовом функции python:
ScriptSource src = py.CreateScriptSourceFromString(@"b + 1");
CompiledCode compiled = src.Compile();
double[] res = new double[1000000];
for(int i=0; i<1000000; i++)
{
pys.SetVariable("b", args1[i]);
res[i] = compiled.Execute(pys);
}
гдеpys - это ScriptScope от py, а args1 - это предварительно созданный массив случайных двойников.Этот пример выполняется медленнее, чем выполнение цикла в коде Python и передача целых массивов.