- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
动态创建动态方法的最佳方法是什么,但如果它是在 VS 中编译的,它又具有相同的效率?
假设我想创建一个计算器。用户输入公式说 A + B/C * 0.5;
我想要的是能够创建类似 Func 的东西,它将接受 A、B、C 作为 double 参数并返回 double 。
参数类型和返回类型总是 double 的。参数的数量是可变的,但至少有一个。
这些公式可以经常更改/添加。一旦一个公式被“编译”,它将成为低延迟代码的一部分,可以被调用 1000 次/秒。
我需要找到简单可靠的方法来构建它,但它必须具有静态构建和优化方法的精确性能质量。
最佳答案
我找到了关于此 (Generating Dynamic Methods ) 的 Microsoft 博客,并比较了静态方法、编译表达式树和 IL 注入(inject)之间的性能。
代码如下:
static void Main(string[] args)
{
double acc = 0;
var il = ILFact();
il.Invoke(1);
var et = ETFact();
et(1);
Stopwatch sw = new Stopwatch();
for (int k = 0; k < 10; k++)
{
long time1, time2;
sw.Restart();
for (int i = 0; i < 30000; i++)
{
var result = CSharpFact(i);
acc += result;
}
sw.Stop();
time1 = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 0; i < 30000; i++)
{
double result = il.Invoke(i);
acc += result;
}
sw.Stop();
time2 = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 0; i < 30000; i++)
{
var result = et(i);
acc += result;
}
sw.Stop();
Console.WriteLine("{0,6} {1,6} {2,6}", time1, time2, sw.ElapsedMilliseconds);
}
Console.WriteLine("\n{0}...\n", acc);
Console.ReadLine();
}
static Func<int, int> ILFact()
{
var method = new DynamicMethod(
"factorial", typeof(int),
new[] { typeof(int) }
);
var il = method.GetILGenerator();
var result = il.DeclareLocal(typeof(int));
var startWhile = il.DefineLabel();
var returnResult = il.DefineLabel();
// result = 1
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Stloc, result);
// if (value <= 1) branch end
il.MarkLabel(startWhile);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ble_S, returnResult);
// result *= (value--)
il.Emit(OpCodes.Ldloc, result);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Starg_S, 0);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Stloc, result);
// end while
il.Emit(OpCodes.Br_S, startWhile);
// return result
il.MarkLabel(returnResult);
il.Emit(OpCodes.Ldloc, result);
il.Emit(OpCodes.Ret);
return (Func<int, int>)method.CreateDelegate(typeof(Func<int, int>));
}
static Func<int, int> ETFact()
{
// Creating a parameter expression.
ParameterExpression value = Expression.Parameter(typeof(int), "value");
// Creating an expression to hold a local variable.
ParameterExpression result = Expression.Parameter(typeof(int), "result");
// Creating a label to jump to from a loop.
LabelTarget label = Expression.Label(typeof(int));
// Creating a method body.
BlockExpression block = Expression.Block(
// Adding a local variable.
new[] { result },
// Assigning a constant to a local variable: result = 1
Expression.Assign(result, Expression.Constant(1)),
// Adding a loop.
Expression.Loop(
// Adding a conditional block into the loop.
Expression.IfThenElse(
// Condition: value > 1
Expression.GreaterThan(value, Expression.Constant(1)),
// If true: result *= value --
Expression.MultiplyAssign(result,
Expression.PostDecrementAssign(value)),
// If false, exit from loop and go to a label.
Expression.Break(label, result)
),
// Label to jump to.
label
)
);
// Compile an expression tree and return a delegate.
return Expression.Lambda<Func<int, int>>(block, value).Compile();
}
static int CSharpFact(int value)
{
int result = 1;
while (value > 1)
{
result *= value--;
}
return result;
}
这是在 i7-920 上进行的 3 次运行。构建 - 发布 x64
583 542 660
577 578 666
550 558 652
576 575 648
570 574 641
560 554 640
558 551 650
561 551 666
624 638 683
564 581 647
-3778851060...
482 482 557
489 490 580
514 517 606
541 537 626
551 524 641
563 555 631
552 558 644
572 541 652
591 549 652
562 552 639
-3778851060...
482 482 560
507 503 591
525 543 596
555 531 609
553 556 634
540 552 640
579 598 635
607 554 639
588 585 679
547 560 643
-3778851060...
平均值:554 549 634
静态 vs IL - IL 快 1% (!) 不知道为什么
静态与 ET - 静态比表达式树快 14%
编辑(2014 年 2 月):我刚刚在 .NET 4.5 和更快的 CPU 上运行上面的代码(稍作修改)并获得了新的结果集:方法/ET - 9%,方法/IL - 4%
因此之前的结果不再有效 - 静态方法调用总是更快..
*不确定它是新硬件 (i7-3820) 还是新 .NET 或者我在旧测试中做错了什么。*
另一个有趣的结果是,在 32 位 中,完全相同的代码显示 3 位之间绝对没有差异。
Method IL ET
--------------------
368 382 399
367 382 399
367 382 399
367 382 400
367 383 400
367 382 399
367 383 399
367 382 399
367 382 399
367 383 400
367 382 399
367 382 399
367 382 399
367 382 399
367 383 400
367 382 400
367 383 399
367 383 400
367 382 399
367 382 400
-7557702120...
--------------------
367.05 382.30 399.35
关于c# - .NET 动态方法。最棒的表演,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10673756/
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and t
我正在开发一个 rdp 虚拟 channel 应用程序。我已经在注册表中注册了客户端 dll 并试图理解,客户端 dll 已加载。但是当从 pEntryPoints 调用 pVirtualChanne
是否可以通过 GPRS(USB 棒)绑定(bind)(聚合)多个连接并将其用作 Linux 中的一个链接? 最佳答案 技术上是可行的。 Linux 有一个名为 bonding 的模块它可以将多个接口(
我的主容器 div 可以刷新,所以它的内容被隐藏/显示。当我的容器 div 隐藏时,我的页脚会弹出。 html 结构如下所示: 注意我已经试过了: 而且它似乎不起作用,当隐藏容器 div 时,页脚 d
我有一个问题,我可以使用 wpa_suppli 进行无线连接 cant on some network, but i need to connect on a network where the SS
我是一名优秀的程序员,十分优秀!