有没有一种快速的方法将歧视的联合转换为字符串?
我试图找出为什么花费数小时将大量记录集合使用各种方法保存到csv文件.我尝试过CsvProvider.Save,sprintf,string builder等等,所有这些都很慢.我想我已经将问题追溯到有区别的联合类型转换.
我的例子说明了这个问题.有没有更好的方法,或者我的"手动转换"是最好的选择.
#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
Run Code Online (Sandbox Code Playgroud)
转换为字符串很慢,因为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
Run Code Online (Sandbox Code Playgroud)
该memoize函数接受一个函数并创建一个函数版本,用于缓存每个输入的输出.对于每个DU情况,该函数在运行一次之后showField应该与函数一样快manual.