.NET队列ElementAt性能

时间:2011-01-10 09:24:18

标签: c# .net queue

我的代码部分工作很困难:

    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。我正在考虑编写自己的Queue,它将使用循环缓冲区。

该代码适用于较低的值。 DisplayedLength是500。

谢谢,

大卫

5 个答案:

答案 0 :(得分:8)

队列没有ElementAt方法。我猜你是通过Linq得到这个,并且它只是对n个元素进行强制迭代,直到它到达所需的索引。随着集合变得越来越大,这显然会变慢。如果ElementAt表示公共访问模式,则选择可通过索引访问的数据结构,例如Array

答案 1 :(得分:4)

是的,链接列表几乎肯定是问题所在。有Queue<T>未实现IList<T> :)的原因(尽管如此,我认为Stack<T>是使用数组实现的,但仍未实现IList<T>可以提供有效的随机访问,但它没有。)

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

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

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

您是否想过直接使用LinkedList<T>?这样可以更容易地从列表末尾轻松阅读项目。

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

答案 2 :(得分:2)

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

答案 3 :(得分:0)

我个人认为队列不是你想要的,但你的访问模式更糟糕。如果要进行顺序访问,请使用迭代器:

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

答案 4 :(得分:0)

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