将 F# 区分联合大小写转换为字符串的速度很慢



我有大约 100k 个被区分的联合案例,我必须转换为字符串,但它似乎非常慢。

作为比较,以下内容平均在 3 秒内执行(在 F# 交互中(:

open System
let buf = Text.StringBuilder()
let s = DateTime.Now
for i in 1 .. 100000 do
Printf.bprintf buf "%A" "OtherFinancingInterest" //string
buf.Length <- 0
printfn "elapsed : %0.2f" (DateTime.Now - s).TotalMilliseconds

虽然以下内容在一分钟内执行(也在 F# 交互中(...

open System
let buf = Text.StringBuilder()
let s = DateTime.Now
for i in 1 .. 100000 do
Printf.bprintf buf "%A" OtherFinancingInterest //DU
buf.Length <- 0
printfn "elapsed : %0.2f" (DateTime.Now - s).TotalMilliseconds

可区分并集有 25 个值(结果仍然非常慢,两种情况约为 16 秒,但比 25 秒少(。知道这是否"正常"或我可能做错了什么吗?

非常感谢

%A格式说明符可以打印任何 F# 值。它使用反射来做到这一点。它应该只真正用于调试目的,而不是在正常的应用程序代码中。

请注意,在第一个示例中使用字符串使用%s可以使其更快,因为在运行时不需要进行类型检查。

对于 DU,您可以使用一个技巧使反射仅在应用程序加载时发生一次:

type FinancingInterest =
| OtherFinancingInterest
open FSharp.Reflection
let private OtherFinancingInterestStringMap =
FSharpType.GetUnionCases typeof<FinancingInterest>
|> Array.map (fun c -> FSharpValue.MakeUnion(c, [||]) :?> FinancingInterest)
|> Array.map (fun x -> x, sprintf "%A" x)
|> Map.ofArray
type FinancingInterest with
member this.AsString = OtherFinancingInterestStringMap |> Map.find this

您还可以将其与%s格式说明符一起使用:

Printf.bprintf buf "%s" OtherFinancingInterest.AsString

在您的示例中,我的时间与您的时间相似,现在这个时间下降到 40 毫秒。

这只有在所有 DU 案例都没有参数的情况下才有效。一旦您尝试这样的事情,您将在应用程序加载时收到异常:

type FinancingInterest =
| Foo of string
| OtherFinancingInterest

说了这么多,我认为你最好写一个简单的函数,将你的类型显式转换为字符串值,必要时重复写出完整的名称。受歧视的工会案例的名称通常不应被视为影响程序的数据。您通常希望能够安全地重命名案例名称,而不会影响运行时行为。

相关内容

  • 没有找到相关文章

最新更新