为什么F#中的printf这么慢? [英] Why is printf in F# so slow?
问题描述
我真的很惊讶F#的printf这么慢.我有许多处理大型数据文件并写出许多CSV文件的C#程序.我最初使用fprintf writer "%s,%d,%f,%f,%f,%s"
开始,认为那将是简单而合理的效率.
I've just been really surprised by how slow printf from F# is. I have a number of C# programs that process large data files and write out a number of CSV files. I originally started by using fprintf writer "%s,%d,%f,%f,%f,%s"
thinking that that would be simple and reasonably efficient.
但是过了一会儿,我有点厌倦了等待文件处理. (我有4gb XML文件要经过并从中写出条目.).
However after a while I was getting a bit fed up with waiting for the files to process. (I've got 4gb XML files to go through and write out entries from them.).
当我通过探查器运行应用程序时,我惊讶地发现printf是一种非常慢的方法.
When I ran my applications through a profiler, I was amazed to see printf as being one of the really slow methods.
我将代码更改为不使用printf,现在性能要好得多. Printf的性能削弱了我的整体应用程序性能.
I changed the code to not use printf and now performance is so much better. Printf performance was killing my overall application performance.
举个例子,我的原始代码是:
To give an example, my original code is:
fprintf sectorWriter "\"%s\",%f,%f,%d,%d,\"%s\",\"%s\",\"%s\",%d,%d,%d,%d,\"%s\",%d,%d,%d,%d,%s,%d"
sector.Label sector.Longitude sector.Latitude sector.RNCId sector.CellId
siteName sector.Switch sector.Technology (int sector.Azimuth) sector.PrimaryScramblingCode
(int sector.FrequencyBand) (int sector.Height) sector.PatternName (int sector.Beamwidth)
(int sector.ElectricalTilt) (int sector.MechanicalTilt) (int (sector.ElectricalTilt + sector.MechanicalTilt))
sector.SectorType (int sector.Radius)
我将其更改为以下
seq {
yield sector.Label; yield string sector.Longitude; yield string sector.Latitude; yield string sector.RNCId; yield string sector.CellId;
yield siteName; yield sector.Switch; yield sector.Technology; yield string (int sector.Azimuth); yield string sector.PrimaryScramblingCode;
yield string (int sector.FrequencyBand); yield string (int sector.Height); yield sector.PatternName; yield string (int sector.Beamwidth);
yield string (int sector.ElectricalTilt); yield string (int sector.MechanicalTilt);
yield string (int (sector.ElectricalTilt + sector.MechanicalTilt));
yield sector.SectorType; yield string (int sector.Radius)
}
|> writeCSV sectorWriter
助手功能
let writeDelimited delimiter (writer:TextWriter) (values:seq<string>) =
values
|> Seq.fold (fun (s:string) v -> if s.Length = 0 then v else s + delimiter + v) ""
|> writer.WriteLine
let writeCSV (writer:TextWriter) (values:seq<string>) = writeDelimited "," writer values
我正在写大约30,000行的文件.没什么特别的.
I'm writing out files with about 30,000 rows. Nothing special.
推荐答案
我不确定这有多重要,但是...
I am not sure how much it matters, but...
检查printf的代码:
Inspecting the code for printf:
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/printf.fs
我知道
// The general technique used this file is to interpret
// a format string and use reflection to construct a function value that matches
// the specification of the format string.
我认为反射"一词可能回答了这个问题.
and I think the word 'reflection' probably answers the question.
printf
非常适合编写简单的类型安全的输出,但是如果您想在内部循环中获得出色的性能,则可能需要使用较低级别的.NET API来编写输出.我还没有做自己的基准测试.
printf
is great for writing simple type-safe output, but if you want good perf in an inner loop, you might want to use a lower-level .NET API to write output. I haven't done my own benchmarking to see.
这篇关于为什么F#中的printf这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!