我有一些非常大的 XML 文件,我使用 System.Xml.Serialization.XmlSerializer
读取这些文件。它非常快(好吧,足够快),但我希望它能汇集字符串,因为一些长字符串会出现很多次。
XML 看起来像这样:
<Report>
<Row>
<Column name="A long column name!">hey</Column>
<Column name="Another long column name!!">7</Column>
<Column name="A third freaking long column name!!!">hax</Column>
<Column name="Holy cow, can column names really be this long!?">true</Column>
</Row>
<Row>
<Column name="A long column name!">yo</Column>
<Column name="Another long column name!!">53</Column>
<Column name="A third freaking long column name!!!">omg</Column>
<Column name="Holy cow, can column names really be this long!?">true</Column>
</Row>
<!-- ... ~200k more rows go here... -->
</Report>
XML 被反序列化成的类看起来有点像这样:
class Report
{
public Row[] Rows { get; set; }
}
class Row
{
public Column[] Columns { get; set; }
}
class Column
{
public string Name { get; set; }
public string Value { get; set; }
}
导入数据时,会为每个列名分配一个新的字符串。我明白为什么会这样,但根据我的计算,这意味着一些重复的字符串占导入数据所用内存的大约 50%。我认为花费一些额外的 CPU 周期来将内存消耗减少一半是一个很好的权衡。有没有什么方法可以让 XmlSerializer
池字符串,以便丢弃重复项并在下次发生 gen0 GC 时回收?
另外,一些最后的说明:
我无法更改 XML 架构。它是从第三方供应商导出的文件。
我知道可以(理论上)使用
XmlReader
制作一个更快的解析器,它不仅可以让我做我自己的字符串池,而且还可以在中期处理数据import 这样在我读完整个文件之前,不必将所有 200k 行都保存在 RAM 中。不过,我宁愿不花时间编写和调试自定义解析器。实际的 XML 比示例稍微复杂一些,因此这是一项非常重要的任务。如上所述 -XmlSerializer
的性能确实足以满足我的目的,我只是想知道是否有一种简单的方法可以稍微调整它。我可以编写自己的字符串池并在
Column.Name
setter 中使用它,但我不想因为 (1) 这意味着摆弄自动生成的代码,并且 (2) 它会引发一系列与并发和内存泄漏相关的问题。不,我所说的“池化”并不是指“实习”,因为这会导致内存泄漏。
最佳答案
就个人而言,我会毫不犹豫地手动启动实体 - 要么通过承担生成代码的所有权,要么手动执行(并摆脱数组 ;-p)。
重新并发 - 你或许可以有一个线程静态池?据我所知,XmlSerializer
只使用一个线程,所以这应该没问题。它还可以让你在完成后把游泳池扔掉。那么你可以有一些东西像一个静态池,但每个线程。然后也许调整 setter :
class Column
{
private string name, value;
public string Name {
get { return this.name; }
set { this.name= MyPool.Get(value); }
}
public string Value{
get { return this.value; }
set { this.value = MyPool.Get(value); }
}
}
其中静态 MyPool.Get
方法与用 HashSet<string>
装饰的静态字段(大概是 [ThreadStatic]
)对话.
关于c# - XmlSerializer 可以池化字符串以避免大的重复字符串吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/713178/