.Net - 从 System.Xml 到 Saxon.Api 性能问题
.Net - Moving from System.Xml to Saxon.Api performance issues
我编写了一个 C# 应用程序来解析非常大的 (100MB+) XML 文件。
我完成它的方法是使用 System.Xml.XmlReader
遍历文件,然后,一旦到达我需要从中收集值的最终节点,我将这些非常小的元素中的每一个转换为a System.Xml.Linq.XElement
并通过 XEelement.XPathEvaluate
执行各种 XPath 语句以获取我需要的数据。
这非常有效,但我遇到了一个障碍,有时我会得到错误的数据,因为 XPathEvaluate
只支持 XPath 1.0 而我的语句是 XPath 2.0(问题发布 ).
我最初执行此操作的代码如下所示:
void parseNode_Old(XmlReader rdr, List<string> xPathsToExtract)
{
// Enter the node:
rdr.Read();
// Load it as an XElement so as to be able to evaluate XPaths:
var nd = XElement.Load(rdr);
// Loop through the XPaths related to that node and evaluate them:
foreach (var xPath in xPathsToExtract)
{
var xPathVal = nd.XPathEvaluate(xPath);
// Do whatever with the extracted value(s)
}
}
根据我在上一个问题中给出的建议,我决定最好的解决方案是从 System.Xml
移动到 Saxon.Api
(支持 XPath 2.0),我当前更新的代码如下所示:
void parseNode_Saxon(XmlReader rdr, List<string> xPathsToExtract)
{
// Set up the Saxon XPath processors:
Processor processor = new Processor(false);
XPathCompiler compiler = processor.NewXPathCompiler();
XdmNode nd = processor.NewDocumentBuilder().Build(rdr);
// Loop through the XPaths related to that node and evaluate them:
foreach (var xPath in xPathsToExtract)
{
var xPathVal = compiler.EvaluateSingle(xPath, (XdmNode)childNode);
// Do whatever with the extracted value(s)
}
}
这是可行的(对我的 XPath 进行了一些其他更改),但它已经慢了大约 5-10 倍。
这是我第一次使用 Saxon.Api 库,这是我想到的。我希望有更好的方法来实现这一点以使代码执行速度具有可比性,或者,如果有人对如何以更好的方式评估 XPath 2.0 语句有其他想法而无需大量重写,我很想听听他们!
任何帮助将不胜感激!!
谢谢!!
更新:
为了自己解决这个问题,我将以下 2 条语句移到了我的构造函数中:
Processor processor = new Processor(false);
XPathCompiler compiler = processor.NewXPathCompiler();
与每次调用此方法时不断重新创建它们相反,这有很大帮助,但该过程仍然比本机 System.Xml.Linq
版本慢约 3 倍。关于实现此解析器的方法的任何其他想法/想法?
这可能是您可以用它做的最好的事情 set-up。
.NET 上的 Saxon 通常比 Java 上的 Saxon 慢 3-5 倍,原因我们从未深究过。我们目前正在探索使用 Excelsior JET 而不是 IKVMC 重建它的可能性,看看这是否可以加快速度。
Saxon 在 third-party DOM 实现上比在其自己的本地树表示上慢得多,但您似乎已更改代码以使用本地树模型。
由于您在每次执行时都解析每个 XPath 表达式,因此您的性能可能受 XPath 编译时间的支配(即使您正在搜索大型 XML 文档)。直到最近,Saxon 的 compile-time 性能才受到很少的关注,因为我们认为在编译时做更多的工作以节省 run-time 的工作量总是值得的;但在这种情况下,情况显然并非如此。可能值得拆分编译和 run-time 并分别测量两者,只是为了看看是否能提供任何见解。例如,它可能会建议关闭某些优化选项。显然,如果您可以缓存和重用已编译的 XPath 表达式,那将会有所帮助。
我编写了一个 C# 应用程序来解析非常大的 (100MB+) XML 文件。
我完成它的方法是使用 System.Xml.XmlReader
遍历文件,然后,一旦到达我需要从中收集值的最终节点,我将这些非常小的元素中的每一个转换为a System.Xml.Linq.XElement
并通过 XEelement.XPathEvaluate
执行各种 XPath 语句以获取我需要的数据。
这非常有效,但我遇到了一个障碍,有时我会得到错误的数据,因为 XPathEvaluate
只支持 XPath 1.0 而我的语句是 XPath 2.0(问题发布
我最初执行此操作的代码如下所示:
void parseNode_Old(XmlReader rdr, List<string> xPathsToExtract)
{
// Enter the node:
rdr.Read();
// Load it as an XElement so as to be able to evaluate XPaths:
var nd = XElement.Load(rdr);
// Loop through the XPaths related to that node and evaluate them:
foreach (var xPath in xPathsToExtract)
{
var xPathVal = nd.XPathEvaluate(xPath);
// Do whatever with the extracted value(s)
}
}
根据我在上一个问题中给出的建议,我决定最好的解决方案是从 System.Xml
移动到 Saxon.Api
(支持 XPath 2.0),我当前更新的代码如下所示:
void parseNode_Saxon(XmlReader rdr, List<string> xPathsToExtract)
{
// Set up the Saxon XPath processors:
Processor processor = new Processor(false);
XPathCompiler compiler = processor.NewXPathCompiler();
XdmNode nd = processor.NewDocumentBuilder().Build(rdr);
// Loop through the XPaths related to that node and evaluate them:
foreach (var xPath in xPathsToExtract)
{
var xPathVal = compiler.EvaluateSingle(xPath, (XdmNode)childNode);
// Do whatever with the extracted value(s)
}
}
这是可行的(对我的 XPath 进行了一些其他更改),但它已经慢了大约 5-10 倍。
这是我第一次使用 Saxon.Api 库,这是我想到的。我希望有更好的方法来实现这一点以使代码执行速度具有可比性,或者,如果有人对如何以更好的方式评估 XPath 2.0 语句有其他想法而无需大量重写,我很想听听他们!
任何帮助将不胜感激!!
谢谢!!
更新:
为了自己解决这个问题,我将以下 2 条语句移到了我的构造函数中:
Processor processor = new Processor(false);
XPathCompiler compiler = processor.NewXPathCompiler();
与每次调用此方法时不断重新创建它们相反,这有很大帮助,但该过程仍然比本机 System.Xml.Linq
版本慢约 3 倍。关于实现此解析器的方法的任何其他想法/想法?
这可能是您可以用它做的最好的事情 set-up。
.NET 上的 Saxon 通常比 Java 上的 Saxon 慢 3-5 倍,原因我们从未深究过。我们目前正在探索使用 Excelsior JET 而不是 IKVMC 重建它的可能性,看看这是否可以加快速度。
Saxon 在 third-party DOM 实现上比在其自己的本地树表示上慢得多,但您似乎已更改代码以使用本地树模型。
由于您在每次执行时都解析每个 XPath 表达式,因此您的性能可能受 XPath 编译时间的支配(即使您正在搜索大型 XML 文档)。直到最近,Saxon 的 compile-time 性能才受到很少的关注,因为我们认为在编译时做更多的工作以节省 run-time 的工作量总是值得的;但在这种情况下,情况显然并非如此。可能值得拆分编译和 run-time 并分别测量两者,只是为了看看是否能提供任何见解。例如,它可能会建议关闭某些优化选项。显然,如果您可以缓存和重用已编译的 XPath 表达式,那将会有所帮助。