[英]BlockingCollection that discards old data
我有一個BlockingCollection 。 生產者任務向其添加項目,消費者任務刪除項目。
現在我想限制集合中的項目數,如果添加更多項目,則自動丟棄舊數據。 該集合永遠不應包含多於N
最近添加的項目。
因此,如果生產者添加新項目的速度快於消費者刪除它們,我希望消費者只處理最新的項目。
我可以在其構造函數中限制BlockingCollection
的大小,但當然這只是意味着它在添加更多項時會阻塞,而不是它會刪除舊項。
(我不希望生產者端阻塞,只有消費者方在從空集合中檢索項目時才會阻塞。)
我目前的解決方案是黑客,只適用於1的大小限制:
(而且我不太確定它是否可靠。)
// My consumer task:
foreach (var item in blockingCollection.GetConsumingEnumerable())
{
var lastItem = item;
var lastItemTmp = item;
while (blockingCollection.TryTake(out lastItemTmp))
lastItem = lastItemTmp;
// Now lastItem contains the most recent item in the collection,
// and older items have been discarded.
// Proceed consuming lastItem ...
}
有更清潔的解決方案嗎?
這樣做:
void AddItemToQueue(MyClass item)
{
while (!queue.TryAdd(item))
{
MyClass trash;
queue.TryTake(out trash);
}
}
如果在嘗試添加項目時隊列已滿,則會從隊列中刪除項目。 它使用TryTake
因為有可能(不太可能,但可能)某個其他線程可能已經從隊列中刪除了最后一個項目,然后才有機會獲取一個。
當然,這假設您在構造BlockingCollection
時指定了項目數限制。
另一種方法是,盡管它涉及的更多,但是要創建自己的循環隊列類,並讓它實現IProducerConsumerCollection接口。 然后,您可以使用該類的實例作為BlockingCollection
的后備集合。 實現循環隊列並不是特別困難,盡管邊緣情況很難實現。 而且你必須使它成為一個並發的數據結構,盡管用鎖很容易。
如果您不希望隊列經常溢出,或者隊列的流量非常低(即每秒沒有被擊中數千次),那么我的初步建議將做您想做的事情並且不存在性能問題。 如果存在性能問題,則循環隊列就是解決方案。
我會使用Concurrent堆棧:
表示線程安全的后進先出(LIFO)集合。
http://msdn.microsoft.com/en-us/library/dd267331%28v=vs.110%29.aspx
我會在堆棧中發送一個包裝你的任務的對象,為它添加一個時間戳。 使用者將從堆棧中獲取任務並丟棄時間戳超過您定義的閾值的任務。
只需在向其中添加項目之前調用此方法即可。
public static void Clear<T>(this BlockingCollection<T> blockingCollection)
{
if (blockingCollection == null)
{
throw new ArgumentNullException("blockingCollection");
}
while (blockingCollection.Count > 0)
{
T item;
blockingCollection.TryTake(out item);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.