【问题标题】:String concatenation optimization in the F# compilerF# 编译器中的字符串连接优化
【发布时间】:2014-02-03 14:16:09
【问题描述】:

C# 编译器足够智能,可以将使用 + 运算符的字符串连接优化为 String.Concat 调用。

以下代码:

var a = "one";
var b = "two";
var c = "three";
var d = "four";

var x = a + b + c + d;

被编译成这个IL:

IL_0000:  ldstr       "one"
IL_0005:  stloc.0     // a
IL_0006:  ldstr       "two"
IL_000B:  stloc.1     // b
IL_000C:  ldstr       "three"
IL_0011:  stloc.2     // c
IL_0012:  ldstr       "four"
IL_0017:  stloc.3     // d
IL_0018:  ldloc.0     // a
IL_0019:  ldloc.1     // b
IL_001A:  ldloc.2     // c
IL_001B:  ldloc.3     // d
IL_001C:  call        System.String.Concat

编译器找出正确的 String.Concat 重载,它接受 4 个参数并使用它。

F# 编译器不这样做。相反,每个+ 都被编译成一个单独的String.Concat 调用:

IL_0005:  ldstr       "one"
IL_000A:  ldstr       "two"
IL_000F:  call        System.String.Concat
IL_0014:  ldstr       "three"
IL_0019:  call        System.String.Concat
IL_001E:  ldstr       "four"
IL_0023:  call        System.String.Concat

显然这是因为 F# 编译器中没有实现这种特殊优化。

问题是为什么:技术上很难做到还是有其他原因?

字符串连接是一种相当常见的操作,虽然我意识到编译代码的性能并不是最重要的,但我想这种优化在很多情况下都会很有用。

【问题讨论】:

    标签: f#


    【解决方案1】:

    我不认为优化有什么难的地方——我认为它没有被实现的主要原因是它特定于字符串连接并且不能更普遍地应用。但是,使用F# open source release 听起来会是一个有趣的项目!

    也就是说,即使是上面完成的 C# 优化也不是那么聪明。编译器没有理由不直接将字符串连接起来,因为它们是常量并产生:

    IL_0000:  ldstr   "onetwothreefour"
    

    换句话说,在添加一些通常有用的东西和添加越来越多的特殊情况之间总是需要权衡取舍——C# 编译器显然还有一些与字符串连接相关的特殊情况......

    【讨论】:

      【解决方案2】:

      我真的很惊讶 F# 编译器没有进行这种优化,因为它通常属于 constants propagation and folding 的保护伞,这是一种常见且相对简单的优化,可以应用于具有已知操作的任何种类的常量编译器(诚然,可能有一些我不知道的注意事项)。

      请注意,C# 巧妙地使用了 4 arg String.Concat 重载,但既不传播也不折叠字符串常量(优点是这种优化同样适用于非常量字符串)。另一方面,F# 正在传播常量,但随后忽略了折叠它们(谁知道呢,也许 JIT 足够聪明,可以进行折叠!)。

      我感兴趣的是 F# 确实折叠 Int16Int32 常量,但 折叠 DoubleFloat 常量(以及那些只是我测试的常量)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-23
        • 2011-06-12
        • 2013-06-07
        • 2011-05-16
        相关资源
        最近更新 更多