有没有一种快速的方法将歧视的联合转换为字符串?
我试图找出为什么花费数小时将大量记录集合使用各种方法保存到csv文件。我试过CsvProvider.Save,sprintf,字符串构建器等等都很慢。我想我已经将问题追溯到有区别的联合类型转换。
我的例子说明了这个问题。有没有更好的方法,或者我的“手动转换”是最好的选择。
#time
open System
type Field = | Ying | Yang
let manual = function | Ying -> "Ying" | Yang -> "Yang"
// Discriminated Union versions
[for i = 0 to 100000 do yield (Ying).ToString()] |> ignore
//Real: 00:00:12.963, CPU: 00:00:13.281, GC gen0: 10, gen1: 0, gen2: 0
[for i = 0 to 100000 do yield (Ying) |> manual] |> ignore
//Real: 00:00:00.004, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
// Others for comparison
[for i = 0 to 100000 do yield (1).ToString()] |> ignore
//Real: 00:00:00.011, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
[for i = 0 to 100000 do yield (1.0).ToString()] |> ignore
//Real: 00:00:00.054, CPU: 00:00:00.062, GC gen0: 0, gen1: 0, gen2: 0
[for i = 0 to 100000 do yield (1.0m).ToString()] |> ignore
//Real: 00:00:00.014, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
转换为字符串很慢,因为DU案例名称实际上是代码的一部分,而不是程序的数据。将其转换为字符串实际上是一种元编程技术,必须达到程序的正常运行时之外,即.NET中的反射。
通常,标识符名称不会影响程序的运行是一件好事,因为这意味着重命名标识符等重构是完全安全的。
但是,如果你真的想这样做并加快速度,我认为最实用的解决方案是使用memoization:
let memoize fn =
let cache = System.Collections.Concurrent.ConcurrentDictionary<'a, 'b>()
(fun x -> cache.GetOrAdd(x, fun _ -> fn x))
let showField : Field -> string = memoize string
memoize
函数接受一个函数并创建一个函数版本,用于缓存每个输入的输出。 showField
函数现在应该与你的manual
函数一样快,因为每个DU情况运行一次。
如果你对格式不太挑剔,可能会使用NewtonSoft.Json序列化集合会更快。
或者您可以尝试将每个DU值附加到StringBuilder,然后在StringBuilder上调用ToString以获取完整的字符串。