是否有一种快速的方法将已区分的并集转换为字符串?
我试图弄清楚为什么要使用各种方法将大量记录保存到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
答案 0 :(得分:6)
转换为字符串很慢,因为DU案例名称实际上是代码的一部分,而不是程序的数据。将其转换为字符串实际上是一种元编程技术,必须超出程序正常运行时的范围,即.NET中的反射。
通常,标识符名称不会影响程序的运行是一件好事,因为这意味着像重命名标识符这样的重构是完全安全的。
但是,如果您真的想做到这一点并使其快速进行,我认为最实用的解决方案是使用备忘录:
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
函数采用一个函数并创建该函数的版本,该版本将缓存每个输入的输出。在每个DU案例中,showField
函数现在应该与您的manual
函数差不多快。
答案 1 :(得分:0)
如果您对格式不太挑剔,也许可以使用NewtonSoft.Json序列化集合。
或者您可以尝试将每个DU值附加到StringBuilder,然后在StringBuilder上调用ToString以获取完整的字符串。