パフォーマンス:LINQ to XML vs XmlDocument vs XmlReader on Desktop and Windows Phone

少し前まで、XMLファイルを操作するWindows Phone用のアプリケーションを作成する必要がありました。 すべてが悪くはありませんでしたが、ファイルに〜100,000レコードがある場合、それらの読み取りには非常に長い時間がかかりました。 そして、.Netプラットフォームで可能なXMLからのデータ読み取りのさまざまな方法のパフォーマンスを比較することにしました。



カットの下の詳細。





装備品



実行されたテストのパフォーマンスをよりよく理解するには、何が行われたかを伝える価値があります。 自宅のコンピューターでデスクトップカテゴリでテストを実行しました。



Windows Phoneでのテストは、HTC 7 Mozartで実行されました。



試験準備



テストでは、単純なxmlファイルが使用されました。 各要素のIDはランダムに生成され、レコードの数はテストによって異なり、それぞれ1、10、100、1,000、100,000個になりました。 結果のファイルは次のようになりました。

<? xml version ="1.0" ? >

< items >

< item id ="433382426" />

< item id ="1215581841" />

< item id ="2085749980" />

........

< item id ="363608924" />

</ items >




* This source code was highlighted with Source Code Highlighter .






エラーを減らすために、各テストを100回実行し、得られたデータを平均しました。 また、レコードに対するいくつかのアクションをシミュレートするために、空のProcessId(id)メソッドが呼び出されました。



XmlDocument.Load



私の意見では、この方法でデータを読み取ることの実装は最も単純で最も理解しやすいものです。 しかし、最後に見るように、これは非常に高いコストで実現されます(記事の最後では、XPathを使用しないこのメソッドの実装が示されていますが、個人的には結果はそれほど変わりません)。 メソッドコードは次のとおりです。

private static void XmlDocumentReader( string filename)

{

var doc = new XmlDocument ();

doc.Load(filename);

XmlNodeList nodes = doc.SelectNodes( "//item" );

if (nodes == null )

throw new ApplicationException( "invalid data" );



foreach ( XmlNode node in nodes)

{

string id = node.Attributes[ "id" ].Value;

ProcessId(id);

}

}



* This source code was highlighted with Source Code Highlighter .








LINQ to XML



また、Linq-to-XMLを使用すると、メソッドの実装が非常に簡単で簡単になります。

private static void XDocumentReader( string filename)

{

XDocument doc = XDocument .Load(filename);

if (doc == null || doc.Root == null )

throw new ApplicationException( "invalid data" );



foreach ( XElement child in doc.Root.Elements( "item" ))

{

XAttribute attr = child. Attribute ( "id" );

if (attr == null )

throw new ApplicationException( "invalid data" );



string id = attr.Value;

ProcessId(id);

}

}



* This source code was highlighted with Source Code Highlighter .








Xmlreader



最後に、XMLからデータを読み取る最後の方法は、XmlTextReaderを使用することです。 この方法が最も理解しにくいと言う価値があります。 xml-fileを読み取るプロセスでは、ファイルを上から下に移動し(反対方向に移動する可能性はありません)、データを抽出する必要があるかどうかを確認する必要がありますか? したがって、メソッドコードは次のようになります。

private static void XmlReaderReader( string filename)

{

using ( var reader = new XmlTextReader (filename))

{

while (reader.Read())

{

if (reader.NodeType == XmlNodeType .Element)

{

if (reader.Name == "item" )

{

reader.MoveToAttribute( "id" );

string id = reader.Value;

ProcessId(id);

}

}

}

}

}



* This source code was highlighted with Source Code Highlighter .






*簡単にするため、メソッドではチェックを省略しました。



デスクトップの結果



以下はテスト結果です。 各テストを実行するために、時間を個別に測定してから平均しました。 テーブル内のミリ秒単位の時間。

1 10 100 1,000 10,000 100,000
XmlDocument 0.59ミリ秒 0.5ミリ秒 0.67ミリ秒 2.49ミリ秒 21.73ミリ秒 398.91ミリ秒
Xmlreader 0.51ミリ秒 0.47ミリ秒 0.55ミリ秒 1.31ミリ秒 8.62ミリ秒 79.65ミリ秒
Linq to XML 0.57ミリ秒 0.59ミリ秒 0.64ミリ秒 2.09ミリ秒 15.6ミリ秒 192.66ミリ秒






表からわかるように、XmlReaderは大きなxmlファイルを読み取るときに、Linq To XMLのパフォーマンスが2.42倍、XmlDocument が5倍以上も優れています



Windows Phoneでのテスト



今が電話でテストを行うときです。 古いバージョンの.Net FrameworkがWindows Phoneにインストールされているため、XmlDocument.Loadを使用するメソッドが機能せず、XmlReaderのコードをわずかに書き換える必要があることに注意してください。

private static void XmlReaderReader( string filename)

{

using ( var reader = XmlReader.Create(filename)) {

while (reader.Read()) {

if (reader.NodeType == XmlNodeType .Element) {

if (reader.Name == "item" ) {

reader.MoveToAttribute( "id" );

string id = reader.Value;

ProcessId(id);

}

}

}

}

}



* This source code was highlighted with Source Code Highlighter .








Windows Phoneの結果



予想通り、XmlReaderは電話でより高速であることが判明しました。 ただし、デスクトップコンピューターとは異なり、大きなファイルでのパフォーマンスの違いは異なります。 XmlReader電話では、LINQ to XMLより1.91倍、デスクトップでは2.42倍高速です。

1 10 100 1,000 10,000 100,000
Xmlreader 1.67ミリ秒 1.74ミリ秒 3.19ミリ秒 19.5ミリ秒 173.84ミリ秒 1736.18ミリ秒
Linq to XML 1.73ミリ秒 2.21ミリ秒 4.75ミリ秒 31.39ミリ秒 314.39ミリ秒 3315.13ミリ秒




デスクトップとWindows Phoneのファイルから100個の要素を読み取る速度の違い。





デスクトップとWindows Phoneのファイルから100,000アイテムを読み取る速度の違い。



ご覧のとおり、データの量に応じて、電話とデスクトップコンピューターでデータを読み取る速度は非線形に変化します。 なぜそうなのかを知るのは興味深い。



おわりに



説明したように、xmlからデータを読み取る最も生産的な方法は、プラットフォームに関係なくXmlReaderを使用することです。 しかし、その使用の不便さは、データをフェッチするためのかなり複雑な方法です-ポインターがどの要素にあるかをチェックするたびに。



パフォーマンスが基礎とならない場合、そして最も重要なことは、コードメンテナンスの明快さと単純さである場合、LINQ to XMLが最適です。 また、パフォーマンスが低いため、作業プロジェクトでXmlDocument.Loadを使用しないようにしてください。



PS この記事が私にこのすべてを書くように促したことに言及する価値があります。



更新:提案で、 alex_rusはXPathを使用せずにXmlDocumentのテストを行いました。 結果は良くなりましたが、それでもこの方法は最も遅いままでした。



表3。XPathを使用した場合と使用しない場合のXmlDocumentのパフォーマンスの比較。

1 10 100 1,000 10,000 100,000
XmlDocument(c XPath) 0.59ミリ秒 0.5ミリ秒 0.67ミリ秒 2.49ミリ秒 21.73ミリ秒 398.91ミリ秒
XmlDocument(XPathなし) 0.56ミリ秒 0.5ミリ秒 0.65ミリ秒 2.24ミリ秒 19.47ミリ秒 362.75ミリ秒




表(および図)からわかるように、生産性はわずか10%増加しました。 この値ははるかに高くなるという提案がありましたが。



実際、XPathを使用しないXmlDocumentのコードは次のとおりです。 知識のある人がエラーのある場所を示し、その結果、処理速度が「時々」ではなく、10%だけ増加することを願っています。

private static void XmlDocumentReader2( string filename)

{

var doc = new XmlDocument ();

doc.Load(filename);



XmlElement root = doc.DocumentElement;

foreach (XmlElement el in root.ChildNodes)

{

if (el.Name != "item" ) continue ;



string id = el.Attributes[ "id" ].Value;

ProcessId(id);

}

}




* This source code was highlighted with Source Code Highlighter .







All Articles