如何通过并行循环优化节点的迭代?

How to optimize the iteration of nodes via parallel lop?

我有一个树列表中的节点列表。

有时我会关闭对列的排序,为了保持相同的 structure/position 节点,我会按原样复制结构,将其放入列表中,并在排序停用后完成我放回了节点位置。这是这样做的:

        List<TreeListNode> nodes = new List<TreeListNode>();
        nodes.AddRange(xtlItemList.Nodes);

        // deactivete sorting
        foreach (var c in xtlItemList.Columns) {
            c.SortOrder = SortOrder.None;
        }

        // put back node positions
        for (int i = 0; i < nodes.Count; i++)
        {
            xtlItemList.SetNodeIndex(nodes[i], i);
        }

问题:

是不是第二个循环需要很多时间来执行。对于 1043 个节点,最多需要 50 秒。

我想我可以通过并行 for 循环优化它:

        int counter = nodes.Count -1;
        try
        {
            Parallel.For
                (0
                 , counter
                 , new ParallelOptions { MaxDegreeOfParallelism = 5 }
                 , (i) =>
                 {
                     try
                     {
                         xtlItemList.SetNodeIndex(nodes[i], i);
                     }
                     catch (Exception exception)
                     {

                         //throw;
                     }
                 }
                );
        }
        catch (Exception exx)
        {


        }

我得到了一些奇怪的结果。大多数情况下,ui 中的节点会消失,有时我会收到空​​引用异常,这让我更加困惑。

我在这里错过了什么?

我假设您在 Windows Forms 应用程序中使用 DevExpress XtraTreeList。

至于 parallel.for,它会在多个线程上执行,这与主 UI 线程不同。从非 UI 线程操作 UI 控件是不安全的,它会导致不可预知的结果:

https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls

Thread-safe calls to WPF controls

另外,我觉得并行循环也不会使它更快,因为进程不涉及后台工作。

我不是 DevExpress UI 控件的专家,但是对于您的实际问题,您可以创建一个额外的隐藏列,在您的 TreeList 中,用原始索引值(例如 1,2)填充它,3..) 并最初按此列对其节点进行排序。然后稍后您可以按照此处的建议再次恢复您的 XtraTreeList 按此列排序:

https://www.devexpress.com/Support/Center/Question/Details/A2372/how-to-clear-column-sorting-and-restore-the-nodes-to-their-original-order

我想这会工作得更快。

希望这有助于解决您的问题..

原来 Devexpress 有 BeginUpdate()EndUpdate() 方法。

我使用了这些,它们大大优化了我的树渲染。修改后的解决方案:

我现在有:

而不是并行
        xtlItemList.BeginUpdate();
        for (int i = 0; i < nodes.Count; i++)
        {
            xtlItemList.SetNodeIndex(nodes[i], i);
        }
        xtlItemList.EndUpdate();

文档:

Begin Method

End Method