【问题标题】:C# Parallel.ForEach XslCompiledTransform vs. Saxon 9.7.0.6 HEC# Parallel.ForEach XslCompiledTransform 与 Saxon 9.7.0.6 HE
【发布时间】:2016-11-10 17:39:17
【问题描述】:

由于 XPath 2.0/XSLT 2.0,我想将我的 XslCompiledTransform 迁移到 Saxon 9.7.0.6 HE,但它比 .NET 慢得多。

我使用默认副本 ident XSLT 和 15.000 个 xml 文件测试了每个版本:

Saxon with Parallel.ForEach: 00:05:02.9013605
XslCompiledTransform with Parallel.ForEach: 00:00:15.6724146

Saxon with foreach: 00:10:09.7763861
XslCompiledTransform with foreach: 00:03:00.3483324

我希望我做错了什么,XslCompiledTransform:

XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xsl);

XmlWriterSettings writerSettings = xslt.OutputSettings.Clone();
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.DtdProcessing = DtdProcessing.Ignore;
readerSettings.XmlResolver = null;

Parallel.ForEach(files, file =>
{
    string target = Path.Combine(output, Path.GetFileName(file));
    using (XmlReader xr = XmlReader.Create(file, readerSettings))
    using (XmlWriter xw = XmlWriter.Create(target, writerSettings))
        xslt.Transform(xr, xw);
});

撒克逊版本:

Processor processor = new Processor();
DocumentBuilder docBuilder = processor.NewDocumentBuilder();
docBuilder.DtdValidation = false;
docBuilder.SchemaValidationMode = SchemaValidationMode.None;
docBuilder.WhitespacePolicy = WhitespacePolicy.PreserveAll;
XsltCompiler compiler = processor.NewXsltCompiler();
XsltExecutable executable = compiler.Compile(new Uri(xsl));

Parallel.ForEach(files, file =>
{
    string target = Path.Combine(output, Path.GetFileName(file));
    XsltTransformer transformer = executable.Load();
    XdmNode input = docBuilder.Build(new Uri(file));
    transformer.InitialContextNode = input;
    Serializer serializer = new Serializer();
    serializer.SetOutputFile(target);
    transformer.Run(serializer);
});

更新

我在没有 Visual Studio 调试的情况下进行了另一次测试,结果好多了:

Saxon: 00:00:41.5990128
XslCompiledTransform: 00:00:19.0441044

所以主要的减速是调试器本身,但仅限于撒克逊人。 现在它只需要.NET版本的两倍时间,它不是超级棒,但我认为我可以这样做。

我可以做些什么来让 Saxon 更快?也许玩代码或使用 EE 而不是 HE?

这里有一些详细的基准信息,主要的性能问题是 DocumentBuilder.Build 方法。但即使是转换本身也比 .NET 版本慢一倍多:

撒克逊人:

.NET:

【问题讨论】:

  • 您是否尝试过不使用 Parallel 运行测试?如果时差发生显着变化,则可能会提示原因。
  • 您使用的是哪个版本的 Saxon,只是为了让我们了解您的比较是基于什么。
  • 我更新了我的问题并添加了正常 foreach 和撒克逊版本的时间。
  • 好吧,如果遇到性能问题,我们还需要知道您是使用 HE 还是 PE 还是 EE 版本,因为商业版本的性能肯定比开源 HE 更好。
  • 我确实使用的是 HE 版本。也许有人可以用PE版本测试它,我不知道可能会有显着的性能差异。

标签: c# xslt saxon parallel.foreach xslcompiledtransform


【解决方案1】:

在性能方面,魔鬼总是在细节中。这听起来像是一个值得做一些详细研究的场景,所以如果你能向我们 (Saxonica) 提供我们运行它所需的一切,我们很乐意看看。

从您的数字中可以看出的第一件事是,MS 处理器通过并行化获得的速度比 Saxon 处理器快得多。这可能是因为 NamePool 争用:与最近的版本相比,我们已经做了很多工作来减少 NamePool 争用,但这是针对“典型工作负载”,我们需要检查,例如,您的文档是否都使用相同的词汇表名字。

我要确定的第一件事是文档构建和转换的成本有多少。根据答案,随后的调查将采取完全不同的过程。 (结果树的序列化成本也可能是一个因素,但这是不寻常的。)

众所周知,Saxon 的 .NET 版本比 Java 版本慢得多。几年前曾经有大约 30% 的开销,但这似乎已经增加,所以现在慢了 3-5 倍,尽管付出了相当大的努力,我们还没有设法找出原因。我们在这里非常依赖 IKVMC 交叉编译器技术和 OpenJDK 库。

【讨论】:

  • 不幸的是,MSFT 没有从 xsl-1.0 继续前进,但在他们的防御中,他们已经生产了一个非常快的处理器,直到今天仍然为其他人设置了高标准竞争。我一直渴望在我的 .net 应用程序中使用 xsl-2(现在是 xsl-3),但每次我查看我的选项时,我都会得出更改成本(不仅仅是产品成本)与利益一直不值得。我发现我可以使用带有 xml.net 的 c# 扩展来实现理想的平衡/妥协。也就是说,我仍然保持警惕并渴望看到 OP 进一步测试的结果。
  • 我很惭愧地承认我使用 Visual Studio 调试器进行了测试。这样主要的性能问题就解决了。你能确认 .NET 的 Saxon 实现慢 2 倍是“可以的”吗?
  • 我同意@PhilBlackburn 的观点,即在性能上很难与 MS 产品竞争。对于大多数人来说,将开发人员的工作效率提高一倍是非常值得的,即使机器性能会有所成本——机器很便宜,开发人员很昂贵;毫无疑问,XSLT 2.0 大大提高了您的生产力;它还为您提供了有助于提高性能的分组和正则表达式等功能。几年前我们进行了一些测量(在 XML London 上报告),根据具体的工作量,比较是高度可变的。
【解决方案2】:

我使用 DocumentBuilder.Build(XmlReader) 为 Saxon 进行了测试并执行了两个测试。

Console.WriteLine("Saxon:");
for (int i = 0; i < 3; i++)
{
    sw.Reset();
    sw.Start();
    Parallel.ForEach(files, file =>
    {
        string target = Path.Combine(output, Path.GetFileName(file));
        XsltTransformer transformer = executable.Load();
        XdmNode input = null;
        using (XmlReader xr = XmlReader.Create(file, readerSettings))
            input = docBuilder.Build(xr);
        transformer.InitialContextNode = input;
        Serializer serializer = new Serializer();
        serializer.SetOutputFile(target);
        transformer.Run(serializer);
    });
    sw.Stop();
    Console.WriteLine("Duration: " + sw.Elapsed);
    RemoveFiles(output);
}

Console.WriteLine("XslCompiledTransform:");
for (int i = 0; i < 3; i++)
{
    sw.Reset();
    sw.Start();
    Parallel.ForEach(files, file =>
    {
        string target = Path.Combine(output, Path.GetFileName(file));
        using (XmlReader xr = XmlReader.Create(file, readerSettings))
        using (XmlWriter xw = XmlWriter.Create(target, writerSettings))
            xslt.Transform(xr, xw);
    });
    sw.Stop();
    Console.WriteLine("Duration: " + sw.Elapsed);
    RemoveFiles(output);
}

结果是:

Saxon: 210.679ms
XslCompiledTransform: 179.129ms

我认为这是一个很好的结果,Saxon 版本只需要比 XslCompiledTransform 版本多 17.61% 的时间。我可以使用 XPath 2.0 和 Xslt 2.0,性能损失只有不到 20%。

撒克逊人:

XslCompiledTransform:

【讨论】:

  • 文本中的计时结果(“Saxon: 179.129ms”、“XslCompiledTransform: 210.679ms”)是否被无意交换了?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 2014-11-04
  • 2014-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多