C#Parallel.ForEach XslCompiledTransform vs. Saxon 9.7.0.6 HE

时间:2016-07-08 08:05:22

标签: c# xslt saxon parallel.foreach xslcompiledtransform

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

我使用默认的copy copy 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

所以主要的减速是调试器本身,但仅限于Saxon。 现在它只需要两倍于.NET版本的时间,它不是非常棒,但我想我可以继续使用它。

我能做些什么来让撒克逊更快?也许玩代码或使用EE而不是HE?

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

撒克逊:

Saxon

.NET:

.NET

2 个答案:

答案 0 :(得分:1)

凭借表演,魔鬼总是处于细节之中。这听起来像是值得做一些详细研究的场景,所以如果你能为我们(Saxonica)提供我们运行它所需的一切,我们很乐意看看。

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

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

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

答案 1 :(得分:0)

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

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%。

撒克逊:

Saxon

XslCompiledTransform:

enter image description here