【发布时间】:2019-11-09 18:48:03
【问题描述】:
我在 C# 中有以下代码: (_StoreQueue 是一个 ConcurrentQueue)
var S = _StoreQueue.FirstOrDefault(_ => _.TimeStamp == T);
if (S == null)
{
lock (_QueueLock)
{
// try again
S = _StoreQueue.FirstOrDefault(_ => _.TimeStamp == T);
if (S == null)
{
S = new Store(T);
_StoreQueue.Enqueue(S);
}
}
}
系统正在实时收集数据(相当高的频率,大约 300-400 次调用/秒)并将其放入代表 5 秒间隔的 bin(存储对象)中。这些 bin 在写入时位于队列中,而在处理和写入数据时队列会清空。
因此,当数据到达时,会检查是否有该时间戳的 bin(以 5 秒舍入),如果没有,则创建一个。
由于这是非常多线程的,系统遵循以下逻辑:
如果有bin,就是用来放数据的。 如果没有 bin,则会启动一个锁,并在该锁内再次进行检查以确保它不是同时由另一个线程创建的。如果仍然没有 bin,则创建一个。
用这个系统,锁大概每2k调用一次
我正在尝试看看是否有办法解除锁定,但这主要是因为我认为必须有一个比仔细检查更好的解决方案。
我一直在考虑的另一种方法是提前创建空箱,这将完全消除对任何锁的需求,但是搜索正确的箱会变得更慢,因为它必须扫描预先构建的列表垃圾箱以找到合适的垃圾箱。
【问题讨论】:
-
System.Collections.Concurrent.ConcurrentQueue不起作用?已经有并发队列数据结构了。 -
这是一个并发队列,但问题是如果2个线程同时尝试写入,一个可能正在创建一个bin,而另一个的bin检查失败(它会创建一个bin也);我刚刚编辑了问题以说明这是一个 ConcurrentQueue,因为这不清楚。
-
您可以使用 ConcurrentQueue,但在排队之前不要聚合 Store 中的数据。如果您让队列数据的使用者将数据聚合成 5 秒的数据包,您的锁定问题就会消失。 (假设您收集的数据量不会造成过度的内存压力)
-
你为什么还要使用
ConcurrentQueue?ConcurrentDictionary将真正解决您的问题,并且只使用 1 行。键是Store.TimeStamp的值类型,值是Store对象 -
elgonzo 的解决方案可行,但它需要在各处进行相当多的更改。字典不会导致类似的问题:一个线程找不到键,创建存储,在创建并添加到字典之前,另一个线程找不到键并自己制作?跨度>
标签: c# concurrency locking