[英]Thread-safe buffer
我正在實現某種緩沖機制:
private static readonly ConcurrentQueue<ProductDto> ProductBuffer = new ConcurrentQueue<ProductDto>();
private async void On_ProductReceived(object sender, ProductReceivedArgs e)
{
ProductBuffer.Enqueue(e.Product);
if (ProductBuffer.Count >= handlerConfig.ProductBufferSize)
{
var products = ProductBuffer.ToList();
ProductBuffer.Clear();
await SaveProducts(products);
}
}
問題是-我是否應該麻煩地添加某種鎖,以確保沒有數據丟失(假設某些其他線程會在buffer.ToList()之后和buffer.Clear()之前添加乘積,假設是:),或ConcurrentQueue將為我處理所有骯臟的工作?
您可以這樣做:
if (ProductBuffer.Count < handlerConfig.ProductBufferSize)
return;
var productsToSave = new List<Product>();
Product dequeued = null;
while(ProductBuffer.TryDequeue(out dequeued))
{
productsToSave.Add(dequeued);
}
SaveProducts(products);
您永遠不會Clear
隊列。 您只要不斷取出東西,直到它變空為止。 如果您不想一次保存太多產品,或者當productsToSave
達到一定大小時可以停止處理,處理該列表,然后開始新的列表。
這樣,是否將新項目添加到隊列都沒有關系。 如果在您從隊列中讀取時添加了它們,它們也會被讀取。 如果是在您停止從隊列中讀取后才添加的,則它們將在那里並在隊列下一次充滿並處理時讀取。
ConcurrentQueue
的要點是,您可以添加到其中並從多個線程中讀取它,而無需lock
。
如果要這樣做:
productsToSave = ProductBuffer.ToList();
ProductBuffer.Clear();
那么您將需要該lock
(這將無法達到目的。)大概您正在使用ConcurrentQueue
因為可能有多個線程將項目添加到隊列中。 如果真是這樣,那么在這兩個語句的執行之間完全有可能進入隊列。 它不會添加到列表中,但會被Clear
刪除。 該項目將丟失。
這是我要實現的方式,我假設不需要在保存完成時通知您?
private void On_ProductReceived(object sender, ProductReceivedArgs e)
{
// Variable to hold potential list of products to save
List<Products> productsToSave;
// Lock buffer
lock(ProductBuffer)
{
ProductBuffer.Enqueue(e.Product);
// If it is under size, return immediately
if (ProductBuffer.Count < handlerConfig.ProductBufferSize)
return;
// Otherwise save products, clear buffer, release lock.
productsToSave = ProductBuffer.ToList();
ProductBuffer.Clear();
}
// Save Produts,
SaveProducts(products);
}
如果您只獲得1種產品,而又什么也沒有得到,怎么辦?您是否不想在超時后保存該產品?
我會在您的用例中使用Rx
東西,尤其是IObservable<T>.Buffer(count)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.