诚然,我���于比较苹果和苹果还是苹果和梨子不确定。但是我特别惊讶于这个差异的大小,本应该期望只有轻微甚至没有差异。
管道经常可以表示为函数组合,反之亦然,我认为编译器也知道这一点,因此我做了一个小实验:
// simplified example of some SB helpers:
let inline bcreate() = new StringBuilder(64)
let inline bget (sb: StringBuilder) = sb.ToString()
let inline appendf fmt (sb: StringBuilder) = Printf.kbprintf (fun () -> sb) sb fmt
let inline appends (s: string) (sb: StringBuilder) = sb.Append s
let inline appendi (i: int) (sb: StringBuilder) = sb.Append i
let inline appendb (b: bool) (sb: StringBuilder) = sb.Append b
// test function for composition, putting some garbage data in SB
let compose a =
(appends "START"
>> appendb true
>> appendi 10
>> appendi a
>> appends "0x"
>> appendi 65535
>> appendi 10
>> appends "test"
>> appends "END") (bcreate())
// test function for piping, putting the same garbage data in SB
let pipe a =
bcreate()
|> appends "START"
|> appendb true
|> appendi 10
|> appendi a
|> appends "0x"
|> appendi 65535
|> appendi 10
|> appends "test"
|> appends "END"
在启用了64位,开启了--optimize
标志的FSI中测试这个命令,会得到以下结果:
> for i in 1 .. 500000 do compose 123 |> ignore;;
Real: 00:00:00.390, CPU: 00:00:00.390, GC gen0: 62, gen1: 1, gen2: 0
val it : unit = ()
> for i in 1 .. 500000 do pipe 123 |> ignore;;
Real: 00:00:00.249, CPU: 00:00:00.249, GC gen0: 27, gen1: 0, gen2: 0
val it : unit = ()
小的差别可以理解,但这是60%的性能下降因素1.6。
我实际上希望大部分工作在StringBuilder
中完成,但显然组合的开销有相当大的影响。
我意识到在大多数实际情况下,这种差异将是微不足道的,但如果你正在编写大型格式化文本文件(如日志文件),就像在这种情况下一样,它会产生影响。
我正在使用最新版本的F#。
--optimize
。如果有影响的话,我也会运行fsianycpu.exe。 - Ringil