2011-10-26 5 views
1

linqを使用してエンジニア向けXMLを生成するコードがここにあります。私はより多くの回答を生成する方法の実際の速度を表示するため誰かがこのlinqを改善するのに役立つかもしれない

こんにちは、以下のコードを追加します私の質問は

public static string CreateXMLforEngineersByLinq(List<Engineers> lst) 
    { 
     string x = "<Engineers>\n"; 
     x += string.Concat(lst.Select(s => 
       string.Format("<Engineer>\n<LicenseID>{0}</LicenseID>\n<LastName>{1}</LastName>\n<FirstName>{2}</FirstName>\n<MiddleName>{3}</MiddleName>\n</Engineer>\n", 
       s.LicenseID, s.LastName, s.FirstName, s.MiddleName))); 
     return x + "</Engineers>"; 
    } 

結果はそれがある。この方法を改善し、スピードアップするための任意の方法でありますそして、リビジョンはここに助ける人の人々:)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using test.Classes; 

namespace test.LINQ 
{ 
public static class BatchOperations 
{ 
    delegate string Operations(List<Engineers> i);   
    public static List<int> BatchAddition(List<int> lstNumbers) 
    { 
     lstNumbers = (from nl in lstNumbers 
         select nl + 2).ToList(); 

     return lstNumbers; 
    } 

    public static string CreateXMLforEngineersTheSimpleWay(IEnumerable<Engineers> lst) 
    { 
     StringBuilder x = new StringBuilder(); 
     x.AppendLine("<Engineers>"); 
     foreach (var s in lst) 
     { 
      x.AppendFormat("<Engineer>\n<LicenseID>{0}</LicenseID>\n<LastName>{1}</LastName>\n<FirstName>{2}</FirstName>\n<MiddleName>{3}</MiddleName>\n</Engineer>\n", 
          s.LicenseID, 
          s.LastName, 
          s.FirstName, 
          s.MiddleName); 
     } 
     x.AppendLine("</Engineers1>"); 
     return x.ToString(); 
    } 

    public static string CreateXMLforEngineersByLinq(List<Engineers> lst) 
    { 
     string x = "<Engineers>\n"; 
     x += string.Concat(lst.Select(s => 
       string.Format("<Engineer>\n<LicenseID>{0}</LicenseID>\n<LastName>{1}</LastName>\n<FirstName>{2}</FirstName>\n<MiddleName>{3}</MiddleName>\n</Engineer>\n", 
       s.LicenseID, s.LastName, s.FirstName, s.MiddleName))); 
     return x + "</Engineers2>"; 
    } 

    public static string CreateXMLforEngineersByLoop(List<Engineers> lst) 
    { 
     string XmlForEngineers = "<Engineers>"; 
     foreach (Engineers item in lst) 
     { 
      XmlForEngineers += string.Format("<Engineer>\n<LicenseID>{0}</LicenseID>\n<LastName>{1}</LastName>\n<FirstName>{2}</FirstName>\n<MiddleName>{3}</MiddleName>\n</Engineer>\n" 
       , item.LicenseID, item.LastName, item.FirstName, item.MiddleName); 
     } 
     XmlForEngineers += "</Engineers3>"; 
     return XmlForEngineers; 
    } 

    public static void ShowEngineersByLicense() 
    { 
     List<Engineers> lstEngr = new List<Engineers>(); 

     Engineers tom = new Engineers(); 
     tom.FirstName = "Tom"; 
     tom.MiddleName = "Brook"; 
     tom.LastName = "Crook"; 
     tom.LicenseID = "1343-343434"; 

     Engineers ken = new Engineers(); 
     ken.FirstName = "ken"; 
     ken.MiddleName = "Brook"; 
     ken.LastName = "Crook"; 
     ken.LicenseID = "1343-343434"; 

     Engineers ben = new Engineers(); 
     ben.FirstName = "ben"; 
     ben.MiddleName = "Brook"; 
     ben.LastName = "Crook"; 
     ben.LicenseID = "1343-343434"; 

     for (int y = 0; y <= 1000; y++) 
     { 
      lstEngr.Add(tom); 
      lstEngr.Add(ken); 
      lstEngr.Add(ben); 
     } 

     List<Operations> j = new List<Operations>(); 
     j.Add(a => CreateXMLforEngineersTheSimpleWay(lstEngr)); 
     j.Add(i => CreateXMLforEngineersByLinq(lstEngr)); 
     j.Add(i => CreateXMLforEngineersByLoop(lstEngr)); 

     DateTime start, end; 
     TimeSpan diff1 = new TimeSpan(); 

     foreach (Operations currentMethod in j) 
     { 
      start = DateTime.Now; 
      Console.Write(currentMethod(lstEngr)); 
      end = DateTime.Now; 
      diff1 = end - start; 
      Console.WriteLine(diff1); 
      Console.Write("\n\n"); 
     } 
    } 
} 

}

+2

ベンチマークを再度行う必要があります。 1:リストに3人以上の人が必要です(10,000を試してみてください)。 2:異なる文字列が割り当てられている必要があります(現実世界で最も可能性が高い)。 C#には不変の文字列があるので、同じ4つの文字列を持つことは信じられないほど速くなります。 Guid.NewGuid()。ToString()を使用します。第3に、テストを複数回(たとえば100回)実行し、平均を取得する必要があります。文字列+ =文字列がStringBuilderよりも優れていると信じるのは非常に難しいです。 – Rob

+1

5000人で動作しています。LINQ:0.019ms、for-Loop:12.059 _seconds_、単純な方法:0.010ms – Rob

+0

私はそのコメントに感謝します。 @Rob –

答えて

1

他の例のすべては、あなたのXMLを生成するために、文字列の連結を使用しています。これの欠点は、あなたの値のいずれかが、XML内でサポートされていない文字(例えば、<および&)を適切にエスケープしていないと失敗することです。 XMLをよりネイティブに扱う方が良いです。次のことを考えてみましょう:あなたはそれを文字列に押し出す前に、メモリ全体XMLを作成するためのメモリのオーバーヘッドを取るしたくない場合

public static string CreateXMLforEngineersByLinq(List<Engineers> lst) 
{ 
    string x = New XElement("Engineers", 
        lst.Select(new XElement, "Engineer", 
         new XElement("LicenseID", s.LicenseID), 
         new XElement("LastName", s.LastName), 
         new XElement("FirstName", s.FirstName), 
         new XElement("MiddleName", s.MiddleName) 
        ) 
       ); 
    return x.ToString(); 
} 

、あなたはXStreamingElement(http://msdn.microsoft.com/en-us/library/system.xml.linq.xstreamingelement.aspx)を使用して検討する必要があります。使用方法の簡単なビデオについては、http://www.microsoft.com/uk/msdn/nuggets/nugget/295/LINQ-to-XML-Streaming-Large-Data-Files-Out-of-Memory.aspxを参照してください。

2

最も明白なスピードアップのためのもの、再び歓迎に感謝している:でStringBuilderを使用します文字列の代わりに。単純連結と比較したStringBuilderのパフォーマンスに関する包括的な説明については、this articleを参照してください。

さらに、これはlinqを完全に省くことによって、より簡単で迅速な解決策を得る1つのケースです。

public static string CreateXMLforEngineersTheSimpleWay(IEnumerable<Engineers> lst) 
    { 
     StringBuilder x = new StringBuilder(); 
     x.AppendLine("<Engineers>"); 
     foreach(var s in lst) 
     { 
       x.AppendFormat("<Engineer>\n<LicenseID>{0}</LicenseID>\n<LastName>{1}</LastName>\n<FirstName>{2}</FirstName>\n<MiddleName>{3}</MiddleName>\n</Engineer>\n", 
          s.LicenseID, 
          s.LastName, 
          s.FirstName, 
          s.MiddleName); 
     } 
     x.AppendLine("</Engineers>"); 
     return x.ToString(); 
    } 

あなたの心がLinqに設定されている場合は、String.Joinメソッドを使用できます。しかし、この解決方法は一時的な配列を作成する必要があるため、これは最初の解決策と同様に機能しないと思われます。

public static string CreateXMLforEngineersByLinq(List<Engineers> lst) 
{ 
    var x = new StringBuilder(); 
    x.AppendLine("<Engineers>)"; 
    x.Append(
       string.Join(
          "\n", 
          lst.Select(s => 
           string.Format(
              "<Engineer>\n<LicenseID>{0}</LicenseID>\n<LastName>{1}</LastName>\n<FirstName>{2}</FirstName>\n<MiddleName>{3}</MiddleName>\n</Engineer>\n", 
              s.LicenseID, 
              s.LastName, 
              s.FirstName, 
              s.MiddleName 
              ) 
          ).ToArray() 
         ); 
     x.AppendLine("</Engineers>"); 
     return x.ToString(); 

} 
+1

なぜStringBuilderはstring.Contact()より高速ですか? – Gleno

+0

'String.Concat'は' StringBuilder'を内部的に使用しています。最初と最後の追加といくつかの 'IEnumerable'オーバーヘッドを除いて、それは速くすべきではありません。 –

+0

こんにちは@Andrew Shepherd私はそこに結果を参照して質問を編集しました:) –

1

は、私はXmlSeriaizerを使用してリスト全体のシリアライズが速くないかどうかをテストするためにworthedことだと思います。

using (var fileStream = new FileStream("engineers.xml", FileMode.OpenOrCreate)) 
{ 
    var xmlSerializer = new XmlSerializer(typeof(List<Engineer>)) 
    xmlSerializer.Serialize(fileStream, list); 
} 
+0

+1;ちょうど私の編集後数分のあなたの答えを今読んでください。私はそれがOPよりも速いと確信しています。いいえ文字列の書式設定... –

+0

おかげで、これを使用して結果を比較しようとしました:)ありがとう –

3

XmlSerializerを使用し、利便性のための拡張メソッドを構築する:このように

public static class XmlExtensions 
{ 
    public static string ToXml<T>(this T instance) 
    { 
     var xmlSerializer = new XmlSerializer(typeof(T)); 
     var stringWriter = new StringWriter(); 
     xmlSerializer.Serialize(stringWriter, instance); 
     return stringWriter.ToString(); 
    } 
} 

public static string CreateXMLforEngineersByLinqMyWay(List<Engineers> lst) 
{ 
    return string.Format("<Engineers>{0}</Engineers>" 
     , string.Join("", 
      lst.Select(s => s.ToXml()) // Might have to put `.ToArray()` here 
      ) 
     ); 
} 

それとも、単にこれを行うことができます:

return lst.ToXml(); 

これは大きなオブジェクトツリーのシリアル化の一部である場合、そしてちょうどこの全体の方法を放棄し、トップレベルのオブジェクトにToXmlを行います。

あなたはそれがXML名前空間をドロップするように取得するためにToXmlメソッドを編集する必要があるかもしれません、など

+0

これは私が期待していたものより少し遅くなってしまった:( –

+0

@Allan:初めてシリアル化にアクセスするのが遅いシリアライゼーションアセンブリは実行時にコンパイルされるため、後続のすべてのアクセスで非常に高速になります。これを避けるには、シリアライゼーションアセンブリをあらかじめコンパイルすることができます。これはVisual Studioのプロジェクトオプションです。 exe'をビルドしてください:http://devolutions.net/articles/dot-net/Net-Serialization-FAQ.aspx#S116 –

+0

@Allan:シリアル化アセンブリを強制的に生成した後、これらのタイミングを100kあらかじめ作成されたエンジニアインスタンス:ToXml:0.42-0.45s、 CreateXmlforEngineersByLinqMyWay:2.5-2.8s(名前空間を削除するためのより低い値、ala [この回答](http://stackoverflow.com/questions/2950658/remove -namespace-from-generated-xml-in-net))、 CreateXmlforEngineersTheSimpleWay:0.25-0.3s、 CreateXmlforEngineersByLinq:0.55-0.65s。 'ToXml'のようなものがMyWayで勝てるかもしれません(私はこれを期待しています。なぜなら、ループは文字列を2回構築する必要があります.1つはフォーマッタで1回、' string.Join'では1回です)。 –

関連する問題