我的代码部分工作很困难:
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。
谢谢,
大卫
答案 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中没有实现,但是有很多第三方实现(如果需要,你可以在以后实现自己的实现)。