我正在比较sprintf用法的性能,并且对我看到的东西感到有点困扰。我测试了以下4种方法,将ClassWithToString的实例传递给每个(除了接收实际整数值的PrintInt)。
type ClassWithToString() =
member this.X = 42
override this.ToString() = this.X.ToString()
let Print item : string =
sprintf "%A" item
let PrintInt item: string =
sprintf "%i" item
let PrintObj item: string =
sprintf "%O" item
let Format item : string =
System.String.Format("{0}", item)
50,000次迭代的结果:
Print (%A): 3143ms
PrintInt (%i): 355ms
PrintObj (%O): 384ms
Format: 8ms
对于“打印”,我理解%A正在使用反射,因此那里的迟缓并不令人震惊,但是对于50k次迭代,我对总时间感到惊讶。在此之后,“PrintInt”和“PrintObj”不使用反射,因此速度提高了一个数量级,这也很有意义。
令我感到困惑的部分是,鉴于String.Format()
sprintf的结果总体上看起来非常缓慢(并且已经在实时应用程序的配置文件中见证过)。为什么sprintf幅度比String.Format()慢?我错过了F#空间有更好的选择吗?
答案 0 :(得分:7)
只有%A使用反射。 %i将是基本情况。
这不是真的。无论您使用哪种说明符,所有printf
函数都需要反射以从格式字符串构造类型安全的打印函数。请查看printf
模块中的this line和this line,了解更多见解。因此,很容易看出为什么sprintf "%i"
仍然比String.Format
慢。
在sprintf "%A"
的情况下,它有一个更高层次的反射,这解释了它可怕的缓慢。
我错过了F#空间中有更好的选择吗?
如果您的目的是构建大字符串,那么StringWriter和StringBuilder可能是最佳选择。如果您为记录目的进行基准测试,FastPrintf是一个很有前途的库。您可以试用this NuGet package声称比内置printf
功能快100倍。