以本地速度运行动态编译的C#代码...如何? [英] Run dynamically compiled C# code at native speed... how?

查看:333
本文介绍了以本地速度运行动态编译的C#代码...如何?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了关于编写和编译动态C#代码的几篇文章。例如,此帖。我明白可以通过几种方法。



但是,调用代码调用器很慢。我做了一个简单的基准测试,比调用本机方法要慢500倍。



我想要做的是相当于加载DLL并调用其中一个方法直接(本地),这将给我想要的速度优势。



最简单的方法是什么?将动态代码编译成dll,然后加载它?可以在记忆中完成吗?



编辑



我不在乎关于编译时间。只有执行。



编辑2,3



这是基准代码写道:

  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 = @ / $优化,
},
@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((2-2)).ToString()+ Environment.NewLine + i.ToString());

t1 = Environment.TickCount; (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; (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 =执行;

t1 = Environment.TickCount; (int j = 0; j< 100000000; j ++)


{
i = funcL(j);
}

t2 = Environment.TickCount;

MessageBox.Show(Delegate:+(t2 - t1).ToString()+ Environment.NewLine + i.ToString());
}


解决方案

是的,如果您通过一个 MethodInfo 或一个非特定的代表,那确实会很慢。诀窍是:不要这样做。各种方法:




  • 对于各种方法,请通过基本的但键入委托,例如 Action ,或作为通用的catch-all, Func< object [],object> - 并使用 Delegate.CreateDelegate 创建一个键入代理:

     动作doSomething =(Action)Delegate.CreateDelegate(typeof(Action),方法); 

    另一个变体是使用 Expression API(它有一个 .Compile()方法)或 DynamicMethod (其中 createDelegate方法())。关键的是:您必须使用键入委托并使用键入调用(而不是 .DynamicInvoke )。 p>


  • 对于您生成整个类型的更复杂的案例,请考虑实现您所了解的界面,即

      IFoo foo =(IFoo)Activator.CreateInstance(...); 

    在初始投票(很便宜)之后,您可以使用静态代码:

      foo.Bar(); 




/ em> 使用 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 use Delegate.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), or DynamicMethod (which has CreateDelegate()). 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆