2013-07-05 3 views
1

VB.NET에 문제가 있습니다. 나는 커스텀 객체 인 "ITNObject"의 배열을 가지고 있는데,이 객체에는 두 개의 요소 인 sting과 int가있다.VB.NET에서 개체 채우기 속도가 느려짐

코드는 일련의 XML 파일을 반복하고 노드를 읽은 다음 마스터 배열에 추가합니다. 목표는 배열을 MySQL 테이블로 출력하는 것입니다.

이제 중요한 비트. 각 루프의 끝에 배열을 쓸 때 (파일 당 한 번) 성능은 선형입니다.

그러나 모든 파일에 대해 배열을 채우고 끝에 한 번 쓰면 배열이 채워짐에 따라 응용 프로그램의 점차 속도가 느려집니다.

끝에 배열에는 수백만 개의 개체가 있습니다.

제안 사항? 아래 코드는 배열이 채워진 부분을 보여줍니다.이 코드는 각 파일에 대해 호출됩니다. 이 예제에서는 전체 파일 세트를 채 웁니다.

느려짐이 중요합니다. 각 파일은 몇 백 루프 (약 100,000 ITNObjects 어레이)가 지나면 파일 당 약 600  ms 느려지고 약ms 걸리는 것으로 시작됩니다.

어떻게 해결할 수 있습니까?

Public Sub ReadITN(filetoDecompress As String) 

    Dim XDoc As Xml.XmlDocument 
    XDoc = New Xml.XmlDocument 
    XDoc.Load(filetoDecompress) 
    Dim nsmgr = New XmlNamespaceManager(XDoc.NameTable) 
    nsmgr.AddNamespace("os", "http://www.ordnancesurvey.co.uk/xml/namespaces/osgb") 

    Dim i As Integer 
    Dim RoadRank As Integer 
    Dim toid() As String 
    Dim x As Integer 
    Dim descNode As XmlNode 
    Dim xmlNodes As XmlNodeList = XDoc.SelectNodes("//os:RoadLink", nsmgr) 
    Dim loopCount As Integer = 0 
    For Each mxmlnode As XmlNode In xmlNodes 'XDoc.GetElementsByTagName("osgb:RoadLink") 
     x = 0 
     ReDim Preserve toid(x) 

     For Each n As XmlNode In mxmlnode.SelectNodes(".//os:referenceToTopographicArea", nsmgr) 
      'If n.Name = "osgb:referenceToTopographicArea" Then 
      ReDim Preserve toid(x) 
      toid(x) = Microsoft.VisualBasic.Right(n.Attributes.Item(0).Value, Len(n.Attributes.Item(0).Value) - 1) 
      x = x + 1 
      'End If 
     Next n 

     descNode = mxmlnode.SelectSingleNode(".//os:descriptiveTerm", nsmgr) 

     RoadRank = 0 
     Select Case UCase(descNode.InnerText) 
      Case "MOTORWAY" : RoadRank = 1 
      Case "A ROAD" : RoadRank = 2 
      Case "B ROAD" : RoadRank = 3 
      Case "MINOR ROAD" : RoadRank = 4 
      Case "LOCAL STREET" : RoadRank = 5 
      Case "PRIVATE ROAD" : RoadRank = 6 
      Case "PRIVATE ROAD - RESTRICTED ACCESS" : RoadRank = 7 
      Case "PRIVATE ROAD - PUBLICLY ACCESSIBLE" : RoadRank = 8 
      Case "PEDESTRIANISED STREET" : RoadRank = 9 
      Case "ALLEY" : RoadRank = 10 
     End Select 

     If toid(0) <> "" Then 

      For i = 0 To x - 1 
       ReDim Preserve ITNObjects(ITNCount) 
       If ITNObjects(ITNCount) Is Nothing Then 
        ITNObjects(ITNCount) = New ITNObject() 
       End If 

       ITNObjects(ITNCount).Toid = toid(i) 
       ITNObjects(ITNCount).RoadRank = RoadRank 
       ITNCount = ITNCount + 1 
      Next i 
     End If 
     Erase toid 
    Next 

    descNode = Nothing 
    xmlNodes = Nothing 
    XDoc = Nothing 
    toid = Nothing 
End Sub 
+3

배열 대신'List (Of T)'를 사용하지 않는 이유는 무엇입니까? 당신은 "ReDim"을 추가 할 때마다 배열을 만들지 만, 선형 시간이 걸리는 것은 당연한 일입니다. 물론 –

답변

3

배열 대신 목록을 사용하십시오.

.NET에서는 배열의 크기를 조정할 수 없습니다. ReDim Preserve 명령은 새 배열을 만들고 이전 배열의 모든 항목을 새 배열에 복사합니다. 배열이 커질수록 당연히 더 오래 걸릴 것입니다.

목록을 작성
Dim ITNObjects as New List(Of ITNObject) 

목록에 항목을 추가

Dim temp as New ITNObject() 
temp.Toid = toid(i) 
temp.RoadRank = RoadRank 
ITNObjects.Add(temp) 
+0

! 그 일을 완벽하게 수행하는 것 같습니다. –

2
ReDim Preserve toid(x) 

당신은 (N^2) 알고리즘 오 작성했습니다. 배열에 새 요소를 추가 할 때마다 모든 이전 요소를 복사해야하는 배열이 만들어집니다. O (n^2) 알고리즘은 n의 큰 값에 대해 제대로 작동하지 않습니다.

지수가 백 오프 할당 전략으로 해결됩니다. 원칙은 간단합니다. 배열이 가득 차면 배열의 크기를 두 배로 늘릴 수 있습니다. 이와 같이 :

If toid.GetUpperBound(0) < x Then ReDim Preserve toid(2 * x) 

.NET 컬렉션 클래스에서 사용하는 전략과 완전히 같습니다. List (Of T)와 마찬가지로 더 좋은 배열 유형입니다.

+0

에 답변 할 시간을내어 주셔서 감사합니다. [Shlemiel의 화가의 알고리즘] (http://www.joelonsoftware.com/articles/fog0000000319.html) –

관련 문제