c# - 了解 C# 中运行时代码生成的各种选项(Roslyn、CodeDom、Linq 表达式,...?)

标签 c# linq jit codedom roslyn

我正在开发一个应用程序,我想在其中动态生成数值计算的代码(为了性能)。作为数据驱动操作来执行此计算太慢。为了描述我的要求,请考虑此类:

class Simulation
{
    Dictionary<string, double> nodes;

    double t, dt;

    private void ProcessOneSample()
    {
        t += dt;
        // Expensive operation that computes the state of nodes at the current t.
    }

    public void Process(int N, IDictionary<string, double[]> Input, IDictionary<string, double[]> Output)
    {
        for (int i = 0; i < N; ++i)
        {
            foreach (KeyValuePair<string, double[]> j in Input)
                nodes[j.Key] = j.Value[i];
            ProcessOneSample();
            foreach (KeyValuePair<string, double[]> j in Output)
                j.Value[i] = nodes[j.Key];
        }    
    }
}

我想要做的是 JIT 编译一个实现 Process 中的外循环的函数。定义此函数的代码将由当前用于实现 ProcessOneSample 的数据生成。为了澄清我的期望,我希望所有字典查找在编译过程中执行一次(即 JIT 编译将直接绑定(bind)到字典中的相关对象),这样当编译的代码实际上是执行后,就好像所有查找都已被硬编码。

我试图找出解决这个问题的最佳工具是什么。我问这个问题的原因是因为有太多选择:

  • 使用罗斯林。当前的障碍是如何将语法中的表达式绑定(bind)到主机程序中的成员变量(即“状态”字典中的值)。 这可能吗?
  • 使用 LINQ 表达式 (Expression.Compile)。
  • 使用 CodeDom。最近我在谷歌搜索中意识到了这一点,以及是什么引发了这个问题。我对在 .Net 中跌跌撞撞地使用第三个编译框架并不太感兴趣。
  • 在知道这些工具存在之前,我最初的计划是调用我自己 JIT 编译的 native 代码 (x86)。我对此有一些经验,但是这里还有很多未知数我还没有解决。如果上述选项的性能不够,这也是我的备份选项。我更喜欢上述 3 种解决方案之一,因为我确信它们会简单得多,假设我可以让其中之一起作用!

有没有人有类似的经验可以分享?

最佳答案

我不确定我是否理解您的示例,也不确定代码生成是否是提高其性能的最佳方法。

但是如果您想了解代码生成选项,请首先考虑您的要求。性能是你想要的,但是还有代码生成的性能,以及生成代码的性能。这些绝对不是同一件事。然后是代码的可写性和可读性。不同的选项在这一点上的得分非常不同。

您的第一个选项是Reflection.Emit ,特别是DynamicMethod 。 Reflection.Emit 是一个相当低级的 API,并且非常高效(即代码生成具有良好的性能)。此外,因为您可以完全控制正在生成的代码,所以您有可能生成最有效的代码(或者显然生成非常糟糕的代码)。此外,您不受 C# 等语言允许执行的操作的限制,CLR 的全部功能都触手可及。 Reflection.Emit 的最大问题是您需要编写大量代码,并且需要深入的 IL 知识。编写该代码并不容易,之后阅读或维护它也不容易。

Linq.Expressions ,更具体地说 Compile method提供一个不错的选择。您可以将其视为本质上是使用 Reflection.Emit 生成 DynamicMethod 的类型安全包装器。生成代码会产生一些开销,这可能不是一个大问题。至于表达自由,您几乎可以做普通 C# 方法中可以做的所有事情。您无法完全控制生成的代码,但质量通常非常好。这种方法的最大优点是使用这种技术编写和读取程序要容易得多。

对于 Roslyn,您可以选择生成语法树,或者生成 C#(或 VB)并将其解析为要编译的语法树。现在猜测性能可能会如何还为时过早,因为我们没有可用的生产代码(在撰写本文时)。显然,解析语法树会产生一些开销,如果您生成单个方法,Roslyn 并行生成多个方法的能力不会有太大帮助。不过,使用 Roslyn 可以实现非常可读的程序。

至于CodeDom,我建议不要使用它。这是一个非常古老的 API,(在当前的实现中)启动 CSC.exe 进程来编译您的代码。我还认为它不支持完整的 C# 语言。

关于c# - 了解 C# 中运行时代码生成的各种选项(Roslyn、CodeDom、Linq 表达式,...?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19075106/

相关文章:

C# "Parameter is not valid."创建新位图

c# - 将派生类的列表转换为基类的列表仍然返回派生类的对象

c# - 避免在 Entity Framework 中重复投影代码

c# - 我可以使用 C# 预处理器跳过 Kinect v2.0 代码吗?

c# - Linq Groupby 分类但我如何操作集合中的值

linq - LINQ订购依据以选择最低的索引

c# - JIT 如何知道在哪里寻找 csc.exe?

c++ - 开源虚拟机

programming-languages - Windows 8 metro/winRT 中的新 JIT 编程语言是否可行?

c# - 允许 SQL Server 代理的 Excel 权限