以原生速度运行动态编译C#代码...怎么样? [英] Run dynamically compiled C# code at native speed... how?

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

问题描述

我已经阅读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


  • 对于更复杂的情况下,要生成整个类型中,需要考虑你了解一个接口,即

     的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 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天全站免登陆