我在VB.NET中遇到了问题。我有一个自定义对象数组,“ITNObject”,它有两个元素,一个sting和一个int。
代码循环遍历一组XML文件,读取节点,然后添加到主阵列。目的是然后将数组输出到MySQL表。
现在,重要的一点。当我在每个循环结束时写入数组(每个文件一次),性能是线性的。
但是,如果我为所有文件填充一个数组,并在结束时写一次,那么随着数组填充,应用程序会逐渐变慢。
最后阵列中有数百万个对象。
有什么建议吗?下面的代码显示了数组填充的部分,为每个文件调用此代码。在这个例子中,它填充了整个文件集。
减速很重要,每个文件开始大约需要15毫秒,经过几百个循环(阵列中大约100,000个ITNObjects)后,每个文件减慢到大约600毫秒。
我该如何解决这个问题?
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
答案 0 :(得分: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)
答案 1 :(得分:2)
ReDim Preserve toid(x)
你写了一个O(n ^ 2)算法。每次向数组添加新元素时,您都要创建一个需要复制所有旧元素的 new 数组。正如你所发现的那样,O(n ^ 2)算法对n的大值表现不佳。
您可以使用所谓的指数退避分配策略解决此问题。原理很简单,只需将数组的大小加倍即可。像这样:
If toid.GetUpperBound(0) < x Then ReDim Preserve toid(2 * x)
.NET集合类使用的策略完全相同。像List(Of T),更好的数组类型。