C# Parallel.ForEach XslCompiledTransform 与 Saxon 9.7.0.6 HE
C# Parallel.ForEach XslCompiledTransform vs. Saxon 9.7.0.6 HE
由于 XPath 2.0/XSLT 2.0,我想将我的 XslCompiledTransform 迁移到 Saxon 9.7.0.6 HE,但它比 .NET 慢得多。
我用默认的复制标识 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版本两倍的时间,不是特别好,但我觉得我可以接受。
我可以做些什么来让 Saxon 更快?也许玩代码或使用 EE 而不是 HE?
这里有一些详细的基准测试信息,主要的性能问题是DocumentBuilder.Build方法。但即使是转换本身也比 .NET 版本慢两倍多:
撒克逊人:
.NET:
在性能方面,细节决定成败。这听起来像是一个值得做一些详细研究的场景,所以如果你能为我们 (Saxonica) 提供我们 运行 它所需的一切,我们很乐意看一看。
从您的数字中可以看出的第一件事是 MS 处理器通过并行化获得比 Saxon 大得多的加速。这可能是因为 NamePool 争用:我们已经做了很多工作来减少最近版本的 NamePool 争用,但那是针对 "typical workloads",我们需要检查,例如,您的文档是否都使用相同的词汇表的名字。
我首先要确定的是文档构建成本和转换成本。根据答案,后续调查将采取完全不同的过程。 (结果树的序列化成本也可能是一个因素,但这并不常见。)
众所周知,Saxon 的 .NET 版本比 Java 版本慢得多。几年前曾经有大约 30% 的开销,但是这似乎增加了,所以现在慢了 3-5 倍,尽管付出了相当大的努力,但我们还没有弄清楚原因。我们在这里非常依赖 IKVMC 交叉编译器技术和 OpenJDK 库。
我使用 DocumentBuilder.Build(XmlReader) for 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:
由于 XPath 2.0/XSLT 2.0,我想将我的 XslCompiledTransform 迁移到 Saxon 9.7.0.6 HE,但它比 .NET 慢得多。
我用默认的复制标识 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版本两倍的时间,不是特别好,但我觉得我可以接受。
我可以做些什么来让 Saxon 更快?也许玩代码或使用 EE 而不是 HE?
这里有一些详细的基准测试信息,主要的性能问题是DocumentBuilder.Build方法。但即使是转换本身也比 .NET 版本慢两倍多:
撒克逊人:
.NET:
在性能方面,细节决定成败。这听起来像是一个值得做一些详细研究的场景,所以如果你能为我们 (Saxonica) 提供我们 运行 它所需的一切,我们很乐意看一看。
从您的数字中可以看出的第一件事是 MS 处理器通过并行化获得比 Saxon 大得多的加速。这可能是因为 NamePool 争用:我们已经做了很多工作来减少最近版本的 NamePool 争用,但那是针对 "typical workloads",我们需要检查,例如,您的文档是否都使用相同的词汇表的名字。
我首先要确定的是文档构建成本和转换成本。根据答案,后续调查将采取完全不同的过程。 (结果树的序列化成本也可能是一个因素,但这并不常见。)
众所周知,Saxon 的 .NET 版本比 Java 版本慢得多。几年前曾经有大约 30% 的开销,但是这似乎增加了,所以现在慢了 3-5 倍,尽管付出了相当大的努力,但我们还没有弄清楚原因。我们在这里非常依赖 IKVMC 交叉编译器技术和 OpenJDK 库。
我使用 DocumentBuilder.Build(XmlReader) for 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: