以原生速度运行动态编译C#代码...怎么样? [英] Run dynamically compiled C# code at native speed... how?
问题描述
我已经阅读SO几个职位有关编写和编译动态C#代码。例如,这个帖子。我知道这是可以做到的几种方法。
但是,调用代码调用缓慢。我做了一个简单的基准,它的一些为500×不是调用本地方法要慢。
我希望能够做的是加载DLL并调用相当于其方法之一,直接(原生),这将会给速度的好处我想要的。
什么是去最简单的方法?动态代码编译为DLL,然后加载它?它可以在内存中完成?
修改
我不在乎大约编译时间。只有执行。
编辑2,3
下面是基准代码我写道:
公共静态INT执行(int i)以{回报我* 2; }
私人无效button30_Click(对象发件人,EventArgs五)
{
CSharpCodeProvider富=新CSharpCodeProvider();
VAR解析度= foo.CompileAssemblyFromSource(
新System.CodeDom.Compiler.CompilerParameters()
{
GenerateInMemory = TRUE,
CompilerOptions = @ /优化,
},
@公共类FooClass {公共静态INT执行(int i)以{回报我* 2;}}
);
变种类型= res.CompiledAssembly.GetType(FooClass);
VAR OBJ = Activator.CreateInstance(类型);
VAR方法= type.GetMethod(执行);
INT I = 0,T1 = Environment.TickCount,T2;
// VAR输入=新对象[] {2};
//为(INT J = 0; J<千万; J ++)
// {
//输入[0] = j的;
// VAR输出= method.Invoke(OBJ,输入);
// I =(int)的输出;
//}
// T2 = Environment.TickCount;
//MessageBox.Show((t2 - T1)的ToString()+ Environment.NewLine + i.ToString());
T1 = Environment.TickCount;
为(INT J = 0; J<亿; J ++)
{
I =执行(J);
}
T2 = Environment.TickCount;
MessageBox.Show(本机+(T2 - T1)的ToString()+ Environment.NewLine + i.ToString());
VAR FUNC =(Func键< INT,INT>)Delegate.CreateDelegate(typeof运算(Func键< INT,INT>),法);
T1 = Environment.TickCount;
为(INT J = 0; J<亿; J ++)
{
I = FUNC(J);
}
T2 = Environment.TickCount;
MessageBox.Show(动态代表:+(T2 - T1)的ToString()+ Environment.NewLine + i.ToString());
Func键< INT,INT> funcL =执行;
T1 = Environment.TickCount;
为(INT J = 0; J<亿; J ++)
{
I = funcL(J);
}
T2 = Environment.TickCount;
MessageBox.Show(代表:+(T2 - T1)的ToString()+ Environment.NewLine + i.ToString());
}
是的,如果您通过调用一个的MethodInfo
或者非特异性代表
,那么它确实会很慢。诀窍是:不这样做的。各种方法:
-
为单个方法,通过一个基本的但类型委托,如去
动作
,或作为一个通用的包罗万象的,Func键< Object []对象,对象>
- 并使用Delegate.CreateDelegate
以创建一个键入委托:动作DoSomething的=(动作)Delegate.CreateDelegate(typeof运算(动作),法);
这样做的另一个变体是使用
表达
API(其中有一个.Compile()
法),或DynamicMethod的
(其中有createDelegate方法()
)。关键的一点:你必须得到一个键入委托并调用使用的键入调用(不是.DynamicInvoke
)。 p> -
对于更复杂的情况下,要生成整个类型中,需要考虑你了解一个接口,即
的IFoo富=(的IFoo)Activator.CreateInstance(...);
再;后的初期投(这是很便宜),你可以只使用静态代码:
foo.Bar();
不要的不是 使用 someDelegate.DynamicInvoke(...)
或 someMethod.Invoke(...)
如果你是任何形式的演出后。
I have read several posts on SO about writing and compiling dynamic C# code. For example, this post. I understand it can be done several ways.
However, calling the code invoker is slow. I did a simple benchmark, and it's some 500 X slower than calling a native method.
What I want to be able to do is the equivalent of loading a DLL and calling one of its methods directly ("natively"), which will give the speed benefits I want.
What is the easiest way to go about this? Compile the dynamic code to a dll and then load it? Can it be done in memory?
EDIT
I don't care about compilation time. Only execution.
EDIT 2, 3
Here is the benchmark code I wrote:
public static int Execute(int i) { return i * 2; }
private void button30_Click(object sender, EventArgs e)
{
CSharpCodeProvider foo = new CSharpCodeProvider();
var res = foo.CompileAssemblyFromSource(
new System.CodeDom.Compiler.CompilerParameters()
{
GenerateInMemory = true,
CompilerOptions = @"/optimize",
},
@"public class FooClass { public static int Execute(int i) { return i * 2; }}"
);
var type = res.CompiledAssembly.GetType("FooClass");
var obj = Activator.CreateInstance(type);
var method = type.GetMethod("Execute");
int i = 0, t1 = Environment.TickCount, t2;
//var input = new object[] { 2 };
//for (int j = 0; j < 10000000; j++)
//{
// input[0] = j;
// var output = method.Invoke(obj, input);
// i = (int)output;
//}
//t2 = Environment.TickCount;
//MessageBox.Show((t2 - t1).ToString() + Environment.NewLine + i.ToString());
t1 = Environment.TickCount;
for (int j = 0; j < 100000000; j++)
{
i = Execute(j);
}
t2 = Environment.TickCount;
MessageBox.Show("Native: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString());
var func = (Func<int, int>) Delegate.CreateDelegate(typeof (Func<int, int>), method);
t1 = Environment.TickCount;
for (int j = 0; j < 100000000; j++)
{
i = func(j);
}
t2 = Environment.TickCount;
MessageBox.Show("Dynamic delegate: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString());
Func<int, int> funcL = Execute;
t1 = Environment.TickCount;
for (int j = 0; j < 100000000; j++)
{
i = funcL(j);
}
t2 = Environment.TickCount;
MessageBox.Show("Delegate: " + (t2 - t1).ToString() + Environment.NewLine + i.ToString());
}
Yes, if you invoke via a MethodInfo
or a non-specific Delegate
, then it will indeed be slow. The trick is: don't do that. Various approaches:
for individual methods, go via a basic but typed delegate, such as
Action
, or as a generic catch-all,Func<object[], object>
- and useDelegate.CreateDelegate
to create a typed delegate:Action doSomething = (Action)Delegate.CreateDelegate(typeof(Action), method);
another variant of this is to use the
Expression
API (which has a.Compile()
method), orDynamicMethod
(which hasCreateDelegate()
). The key thing: you must get a typed delegate and invoke using typed invoke (not.DynamicInvoke
).for more complex cases where you are generating whole types, consider implementing an interface you know about, i.e.
IFoo foo = (IFoo)Activator.CreateInstance(...);
again; after the initial cast (which is very cheap) you can just use static code:
foo.Bar();
Do not use someDelegate.DynamicInvoke(...)
or someMethod.Invoke(...)
if you are after any kind of performance.
这篇关于以原生速度运行动态编译C#代码...怎么样?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!