Delphi XML(MSXML)例程的二次运行时

sch*_*der 7 xml delphi performance

在工作中,我们使用的是XML日志文件.每个日志消息是<message>与块<date><time>子节点,还有<submessage>块,<table>构建体等和日志文件可以被转换成使用一些Delphi的处理和以后的XSLT的局部HTML.

对于中等大小的日志文件(大约2 MB),我们遇到了性能问题(加载XML并进行一些基本操作需要一分钟),我可以将它们缩减为这样的测试项目(编辑:更新了代码并添加了测量结果) ):

procedure TForm1.PrepareTest(MessageCount : integer);
var
  XML : IXMLDocument;
  i : integer;
begin
  XML := NewXMLDocument;
  XML.DocumentElement := XML.CreateNode('root');
  for i := 1 to MessageCount do
  begin
    XML.DocumentElement.AddChild('message').Text := 'Test Text';
  end;
  XML.SaveToFile(XML_NAME);
end;

procedure TForm1.XMLTest;
var
  StartTime : Cardinal;
  XML : IXMLDocument;
begin
  StartTime := GetTickCount();
  XML := NewXMLDocument;
  XML.LoadFromFile(XML_NAME);
  Memo1.Lines.Add('Node count: ' + IntToStr(XML.DocumentElement.ChildNodes.Count));
  Memo1.Lines.Add('Time: ' + FloatToStr((GetTickCount() - StartTime) / 1000) + ' seconds');
end;
Run Code Online (Sandbox Code Playgroud)

这导致以下时间测量(每列节点计数增加25%,所有时间以毫秒为单位):

Node count      8000    10000   12500   15625   19531   24413   30516   38145   47681
Base test time  484     781     1140    1875    2890    4421    6734    10672   16812
Variation 1                             32      47      62      78      78      141
Variation 2     2656    3157    3906    5015    6532    8922    12140   17391   24985
  (delta Base)   2172    2376    2766    3140    3642    4501    5406    6719    8173
Run Code Online (Sandbox Code Playgroud)

请注意这两个变体,第一个是LoadFromFile唯一的,第二个是额外添加10000个节点到XML的开头(!)PrepareTest,这是最坏的情况,但查看基础测试的增量,即使这不是显示二次效应.另请注意,计数节点可以替换为任何其他操作,因此看起来有一些延迟的初始化/验证涉及导致问题的XML文件,之后的任何操作都会显示预期的行为.

内存使用率不高,最后一个测试用例(47681个节点)的峰值内存使用量为39 MB,其XML文件大小为1.3 MB.

在加载XML之后做的第一件事(例如,读取或写入一些节点或访问节点计数)很慢并且它显示二次运行时行为,因此任何高于10 MB的日志文件都是不可用的.

通过解析100个消息的小块,我们已经解决了性能问题以及其他一些问题,并且我知道Delphi XML例程不适合/用于此用例 - 使用不同的XML库很可能会阻止性能问题.所以我不是要求解决问题的方法(尽管知道如果不使用不同的XML库就可以解决问题会很有趣).

我的问题是:Delphi XML例程的二次运行时行为分别是MSXML的原因是什么?我无法想象在XML加载/解析/验证中会导致这种情况的事情,除了真正"愚蠢"的事情,比如管理链表而不是树中的节点,但我可能会忽略某些东西,也许是DOM相关的.

Sti*_*ers 7

我同意mj2008,XML不适合日志记录.也就是说,这个问题和一般的大型XML文件可以通过使用SAX更快地处理,它在解析传入的XML数据流时抛出事件,这使您可以在从磁盘读取项目时处理这些项目,实际上减轻了指数在将其交给XSLT之前将其全部加载到内存中.

我很遗憾我还没有在Delphi中完成SAX,但我怀疑最困难的部分是实现所需的SAX接口(例如ISAXContentHandler),但是Delphi有TInterfacedObject和TAutoObject等等.