如何在f#中实现高效的字符串实习?

时间:2017-04-30 22:52:47

标签: string f# string-interning

在f#中为实习字符串实现自定义字符串类型是什么。我必须将大型csv文件读入内存。鉴于大多数列都是分类的,值是重复的,在第一次遇到它时创建新字符串是有意义的,并且只在后续事件中引用它以节省内存。

在c#中,我通过创建全局实习池(并发dict)并在设置值之前执行此操作,查找字典(如果已存在)。如果它存在,只需指向字典中已有的字符串。如果没有,请将其添加到字典中,并将值设置为刚刚添加到字典中的字符串。

f#的新手,想知道在f#中执行此操作的最佳方法是什么。将在名为元组等的记录中使用新的字符串类型,它将必须使用并发进程。

编辑: String.Intern使用实习池。我的理解是,对于大型池并不是非常有效,并且不是垃圾收集,即任何/所有实施的字符串将在应用程序的生命周期内保留在实习池中。想象一个应用程序,您可以在其中读取文件,执行某些操作并写入数据。使用Intern Pool解决方案可能会有效。现在假设您必须执行相同的100次并且每个文件中的字符串几乎没有共同之处。如果在堆上分配内存,则在处理完每个文件后,我们可以强制垃圾收集器清除不必要的字符串。

我应该提到我无法弄清楚如何在F#中进行C#方法(除了实现C#类型并在F#中使用它)

记忆模式与我想要的略有不同?我们不缓存计算结果 - 我们确保每个字符串对象创建不超过一次,并且相同字符串的所有后续创建只是对原始对象的引用。使用字典来执行此操作是一种方法,使用String.Intern是另一种方式。

抱歉,如果我遗漏了一些明显的东西。

1 个答案:

答案 0 :(得分:1)

我有几点要说,所以我会将它们作为答案发布。

首先,我猜String.Intern在F#和C#中的效果一样。

let x = "abc"
let y = StringBuilder("a").Append("bc").ToString()
printfn "1 : %A" (LanguagePrimitives.PhysicalEquality x y) // false
let y2 = String.Intern y
printfn "2 : %A" (LanguagePrimitives.PhysicalEquality x y2) // true

其次,您在C#解决方案中使用字典与String.Intern结合使用吗?如果是这样,为什么不在文件输入后字符串准备好后再进行s = String.Intern(s);

创建一个在您的业务领域中使用的类型来处理字符串重复数据删除通常是一个非常糟糕的主意。您不希望您的业务域受到那种低级别内容的污染。

至于自己滚动。几年前我这样做了,可能是为了避免你提到的字符串没有被垃圾收集的问题,但我从未测试过这是否真的是一个问题。

对于每个列(或列的类型)使用字典(或其他内容)可能是一个好主意,其中相同的值可能会大量重复。 (这几乎就是你所说的。)

只有在您从文件中读取信息并将其填充到内部数据结构中时,才能使这些词典保持有效。你可能会认为你需要字典来进行后续阅读,但我对此并不十分肯定。

  • 重要的是重复删除绝大多数字符串,而不一定是每一个重复字符串。因此,您可以大大简化解决方案。通过过度复杂的解决方案来挤出最后一部分内存节省,你很可能没有任何好处。
  • 在读取文件并填充结构后释放字典将具有在不再需要字符串时不保留字符串的优点。当然,你不要坚持使用词典来节省记忆。

我认为这里不需要处理实现中的并发问题。 String.Intern必须不受并发问题的影响。如果您使用建议的设计自行滚动,则不会同时使用它。正在读取的每个文件的列都有自己的字典集。