[英]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.