【问题标题】:Optimize nested for loop优化嵌套for循环
【发布时间】:2016-01-14 09:23:05
【问题描述】:

我正在将 GMAP.Net 库用于映射 Windows 应用程序。 我的 Sql Server 数据库上有大约 17000 个多边形。在表单加载事件中,我从数据库中选择所有多边形并填充数据表,然后从数据表中一一绘制多边形。 我还有一个树视图,我将所有 17000 个多边形名称添加到该树视图中。 现在,当我选中 treeview 上的全选复选框时,我会在 Treeview node_AfterCheck 事件中调用一个函数,如下所示:

Private Sub node_AfterCheck(sender As Object, e As TreeViewEventArgs)     Handles TreeView1.AfterCheck

   If e.Action <> TreeViewAction.Unknown Then
      Task.Factory.StartNew(Sub()
                                  GetPolygons(e.Node)
                              End Sub, TaskCreationOptions.LongRunning)
   End If
End Sub



Private Sub GetPolygons(node As TreeNode)
            Dim objectId As String
            Dim _polygon As GMapPolygon
            For Each node1 As TreeNode In node.Nodes
                objectId = node1.Name

                For Each _polygon In polyOverlay.Polygons.AsParallel
                    itemTag = _polygon.Tag.ToString.Split("|")
                    If itemTag (0) = node1.Name Then
                        _polygon.IsVisible = node.Checked
                        Exit For
                    End If
                Next
            Next
End sub

此代码大约需要 40 秒才能完全运行。有没有办法优化这段代码以在更短的时间内完成?

【问题讨论】:

  • 另外End IfExit For的顺序也有问题。

标签: optimization treeview nested-loops gmap.net


【解决方案1】:

我可以看到在代码方面昂贵的一件事是在多边形标签上调用Split。但这需要衡量。

要绕过Split,您可以例如尝试使用:

If _polygon.Tag.StartsWith(node1.Name) Then

考虑this question 以了解IsPrefix 在您的情况下是否更快。

但是,我假设主要问题是在设置每个多边形的可见性时不断刷新/重绘地图(“自动刷新”)。我在来源中发现的一件事是将Invalidation 设置为暂停:

// docs: stops immediate markers/route/polygon invalidations; call Refresh to perform single refresh and reset incalidation state
gmap2.HoldInvalidation = true;

// do your update loop within here

// docs: call this to stop HoldInvalidation and perform single forced instant refresh
gmap2.Refresh();

目前还没有机会尝试,但我想你可以继续尝试,看看是否会有所作为。

【讨论】:

    【解决方案2】:

    感谢您的快速回复,我将代码更改如下:

    Private Sub GetPolygons(node As TreeNode)
    
            myMap.HoldInvalidation = True
    
            Dim objectId As String
            Dim _polygon As GMapPolygon
            For Each node1 As TreeNode In node.Nodes
                objectId = node1.Name
    
                For Each _polygon In polyOverlay.Polygons.AsParallel
                    itemTag = _polygon.Tag.ToString.Split("|")
                    If itemTag (0) = node1.Name Then
                        _polygon.IsVisible = node.Checked
                        Exit For
                    End If
                Next
            Next
    
            myMap.Refresh()
    

    结束子

    但是代码比以前需要更多的时间来完成。

    【讨论】:

    • 通过将 "_polygon.Tag.ToString.Split("|")" 替换为 "_polygon.Tag.StartsWith(node1.Name)" 现在代码需要大约 20 秒而不是 40 秒。跨度>
    • 好的,值得一试。 17000 个多边形相当多,很高兴看到删除 Split 操作有所帮助,在没有对每个字符串进行任何操作的情况下可能仍然更好,认为这可能吗?该操作实际上需要多少时间?通过完全忽略可见性设置来尝试缩小瓶颈所在的位置来找出答案。让我们看看我们从那里得到什么,我想知道。
    • 如果不对每个字符串进行操作,大约需要 2 秒才能完成!
    • 好消息,是时候重构 string 退出循环了。现在您已经知道可能重要的实际秒数,如果HoldInvalidation 确实重要,我会很感兴趣。
    • 无 HoldInvalidation 无关紧要。但好消息!我将polygonId 放在polygon.name 而不是polygon.tag 现在我只检查:“如果string.CompareOrdinal(_polygon.Name, node1.Name) = 0 Then _polygon.IsVisible = node.Checked Exit For End If”现在大约需要5秒完成。现在如果我可以删除它如果我认为它会更优化
    猜你喜欢
    • 2012-01-27
    • 2020-05-18
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 2020-08-28
    相关资源
    最近更新 更多