【问题标题】:.NET queue ElementAt performance.NET 队列 ElementAt 性能
【发布时间】:2011-01-10 09:24:18
【问题描述】:

我的部分代码很难处理:

    private void UpdateOutputBuffer()
    {
        T[] OutputField = new T[DisplayedLength];

        int temp = 0;
        int Count = HistoryQueue.Count;
        int Sample = 0;

        //Then fill the useful part with samples from the queue
        for (temp = DisplayStart; temp != DisplayStart + DisplayedLength && temp < Count; temp++)
        {
            OutputField[Sample++] = HistoryQueue.ElementAt(Count - temp - 1);
        }

        DisplayedHistory = OutputField;
    }

大部分时间都在程序中。 HistoryQueue 中的元素数量为 200k+。 这可能是因为.NET 中的队列在内部是作为链表实现的吗?

有什么更好的方法来解决这个问题? 基本上,该类应该像一个 FIFO 一样开始丢弃大约 500k 个样本的元素,我可以选择 DisplayedLength 元素并将它们放入 OutputField。我正在考虑编写自己的使用循环缓冲区的队列。

代码在计算较低的值时运行良好。 DisplayedLength 为 500。

谢谢你,

大卫

【问题讨论】:

    标签: c# .net queue


    【解决方案1】:

    队列没有ElementAt 方法。我猜你是通过 Linq 得到的,它只是对 n 个元素进行强制迭代,直到它达到所需的索引。随着收藏变得越来越大,这显然会放慢速度。如果ElementAt 代表一个常见的访问模式,那么选择一个可以通过索引访问的数据结构,例如一个Array

    【讨论】:

    • 大多数 LINQ 运算符都可以从实现IList&lt;T&gt; 的输入的索引访问检查中受益(Array 会这样做)。
    • 只是不要将数组公开。最好将其公开为IEnumerable&lt;T&gt;IList&lt;T&gt;,以哪个更合适。
    • @daqq 我要补充一点,如果您需要对您的集合进行索引访问,那么 Queue 可能是错误的使用方法;您的代码中可能存在更大的设计问题。
    【解决方案2】:

    是的,链接列表几乎肯定是问题所在。 Queue&lt;T&gt; 没有实现 IList&lt;T&gt; 是有原因的 :)(话虽如此,我相信 Stack&lt;T&gt; 是使用数组实现的,但仍然没有实现 IList&lt;T&gt;。它可以 em> 提供有效的随机访问,但它没有。)

    我无法轻易判断您要显示队列的哪一部分,但我强烈怀疑您可以简化方法使用以下方法使其更高效:

    T[] outputField = HistoryQueue.Skip(...) /* adjust to suit requirements... */
                                  .Take(DisplayedLength)
                                  .Reverse()
                                  .ToArray();
    

    这仍然需要单独跳过大量项目,但至少只需执行一次。

    你有没有想过直接使用LinkedList&lt;T&gt;?这样可以更轻松地从列表末尾读取项目。

    当然,使用循环缓冲区构建您自己的有界队列并不难,而且从长远来看可能是更好的解决方案。

    【讨论】:

      【解决方案3】:

      这里使用的数据结构绝对是错误的。 ElementAt 是 O(n),这使得你的循环 O(n2)。您应该使用其他东西而不是队列。

      【讨论】:

        【解决方案4】:

        就我个人而言,我不认为队列是您要寻找的,但您的访问模式更糟。如果您想要顺序访问,请使用迭代器:

        foreach(var h in HistoryQueue.Skip(DisplayStart).Take(DisplayedLength).Reverse())
            // work with h
        

        【讨论】:

        • 看起来他在队列中倒退,而不是前进。但是,是的,我同意。如果你要按顺序做某事,你应该使用迭代器或具有 O(1) 索引访问的东西。
        【解决方案5】:

        如果您需要能够在任一端弹出/推送并且具有索引访问权限,您确实需要实现Deque(多数组形式)。虽然 BCL 中没有实现,但有很多第三方实现(开始,如果需要,您可以稍后实现自己的)。

        【讨论】:

        • @Qwertie:快速search 发现很多,但我没有时间审查质量以提出可以作为推荐的东西。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-03-08
        • 2012-05-14
        • 2020-10-15
        • 2018-06-01
        • 1970-01-01
        • 2018-08-01
        • 2014-05-07
        相关资源
        最近更新 更多