2011-10-26 3 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>"; 
    } 

결과이 방법을 속도를 어떤 방법이있다 에 StringBuilder를 사용, 수정 및 환영 덕분에 여기에 도움이 :) 사람들이

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()을 사용하십시오.셋째, 테스트를 여러 번 (예 : 100) 실행하고 평균을 가져와야합니다. 나는 문자열 + = 문자열이 StringBuilder보다 뛰어나다 고 믿는다. – Rob

+1

5000 명의 사람들과 달리기 때문에 결과는 다음과 같다. LINQ : 0.019ms, for-Loop : 12.059 _seconds_, 간단한 방법 : 0.010ms – Rob

+0

나는 그 주석을 고맙게 여기고있다. @ Roob –

답변

1

다른 모든 예제 등 당신이 XML 네임 스페이스를 드롭 얻기 위해 ToXml 방법을 수정해야 할 수도 있습니다

, 당신의 XML을 생성하는 문자열 CONCAT를 사용하고 있습니다. 단점은 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의 성능에 대한 포괄적 인 설명은 this article을 참조하십시오.

또한 linq을 함께 사용하지 않아도보다 간단하고 빠른 솔루션을 얻을 수 있습니다.

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을한다.

+0

이것은 내가 기대하는 것보다 조금 느려지 게되었습니다. ( –

+0

@Allan : 처음 직렬화에 액세스 할 때 속도가 느립니다. 왜냐하면 직렬화 어셈블리가 런타임에 컴파일 될 것이기 때문에 모든 후속 액세스에서 훨씬 더 빠를 것입니다. 이것을 피하려면 직렬화 어셈블리를 미리 컴파일 할 수 있습니다. 이것은 Visual Studio의 프로젝트 옵션이거나'sgen '을 추가 할 수 있습니다. exe'를 빌드하십시오. http://devolutions.net/articles/dot-net/Net-Serialization-FAQ.aspx#S116 –

+0

@Allan : 직렬화 어셈블리를 강제 생성 한 후,이 타이밍을 100k 미리 만들어진'Engineer' 인스턴스 : ToXml : 0.42-0.45s, CreateXmlforEngineersByLinqMyWay : 2.5-2.8s (네임 스페이스를 제거하기위한 낮은 값, ala [이 답변] (http://stackoverflow.com/questions/2950658/remove) -namespace-from-generated-xml-in-net)), CreateXmlforEngineersSimpleWay : 0.25-0.3s, CreateXmlforEngineersByLinq : 0.55-0.65s. 'ToXml'처럼 MyWay에서 이길 수 있습니다 (루프가 문자열을 두 번 작성해야하기 때문에 일종의, formatter에서 한 번,'string.Join'에서 한 번). –

관련 문제