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

2024-01-27

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

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 编译将直接绑定到字典中的相关对象),这样当编译的代码实际上是执行后,就好像所有查找都已被硬编码。

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

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

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


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

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

你的第一个选择是反射.发射 http://msdn.microsoft.com/en-us/library/system.reflection.emit.aspx, 尤其动态方法 http://msdn.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx。 Reflection.Emit 是一个相当低级的 API,并且非常高效(即代码生成具有良好的性能)。此外,因为您可以完全控制正在生成的代码,所以您有可能生成最有效的代码(或者显然生成非常糟糕的代码)。此外,您不受 C# 等语言允许执行的操作的限制,CLR 的全部功能都触手可及。 Reflection.Emit 的最大问题是您需要编写大量代码,并且需要深入的 IL 知识。编写该代码并不容易,之后阅读或维护它也不容易。

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐