C# 组合ConcurrentQueue和ConcurrentStack
我正在寻找一个同时收集,可以从双方访问。我希望实现以下目标:C# 组合ConcurrentQueue和ConcurrentStack,c#,.net,multithreading,collections,C#,.net,Multithreading,Collections,我正在寻找一个同时收集,可以从双方访问。我希望实现以下目标: 一些制作人添加了一些项目 客户应能够显示最近生产的n个项目 该集合应仅包含最近x小时内产生的元素 因此,我需要访问列表的顶部(FIFO)来显示最后n个项目,但我还需要访问列表的末尾(LIFO)来连续删除超过x小时的元素 客户应能够显示最近生产的n个项目 这与删除项目无关。我想你想让他们在展示完后留在那里。 所以你并不真的想要后进先出的部分 当项目数量不太大时,可以使用ConcurrentQueue和ToArray()获取快照(并且
- 一些制作人添加了一些项目
- 客户应能够显示最近生产的n个项目
- 该集合应仅包含最近x小时内产生的元素
当项目数量不太大时,可以使用ConcurrentQueue和ToArray()获取快照(并且只使用前n个项目) 另一种方法是使用
MemoryCache
类,它是线程安全的,并提供用于删除“过期”项目的内置功能
我创建了一个类来保存保存的值和时间戳
public class SavedItem<T>
{
public DateTime Timestamp { get; set; }
public T Value { get; set; }
}
公共类SavedItem
{
公共日期时间时间戳{get;set;}
公共T值{get;set;}
}
Collection类将有两个方法:一个用于添加,另一个用于检索N个最后项目的数量
public class ExpiredCollection
{
private readonly MemoryCache _cache;
private readonly int _hoursLimit;
public ExpiredCollection(int hoursLimit)
{
_cache = new MemoryCache("sample");
_hoursLimit = hoursLimit;
}
public void Add<T>(T value)
{
var item = CreateCacheItem(value);
var policy = CreateItemPolicy();
_cache.Add(item, policy);
}
private CacheItem CreateCacheItem<T>(T value)
{
var addedValue = new SavedItem<T>
{
Timestamp = DateTime.Now,
Value = value
};
// Create unique key to satisfy MemoryCache contract
var uniqueKey = Guid.NewGuid().ToString();
return new CacheItem(uniqueKey, addedValue);
}
private CacheItemPolicy CreateItemPolicy()
{
// This will set a time when item will be removed from the cache
var expirationTime = DateTime.Now.AddHours(_hoursLimit);
var offset = new DateTimeOffset(expirationTime);
return new CacheItemPolicy
{
AbsoluteExpiration = offset
};
}
public IEnumerable<T> GetLast<T>(int amount)
{
return _cache.Select(pair => (SavedItem<T>)pair.Value)
.OrderBy(item => item.Timestamp)
.Select(item => item.Value)
.Take(amount);
}
}
公共类过期集合
{
私有只读存储器缓存;
私有只读时间限制;
公共过期集合(整数小时限制)
{
_缓存=新的内存缓存(“样本”);
_小时限制=小时限制;
}
公共无效添加(T值)
{
var item=CreateCacheItem(值);
var policy=CreateItemPolicy();
_cache.Add(项、策略);
}
private CacheItem CreateCacheItem(T值)
{
var addedValue=新的SavedItem
{
时间戳=日期时间。现在,
价值=价值
};
//创建唯一密钥以满足MemoryCache契约
var uniqueKey=Guid.NewGuid().ToString();
返回新的缓存项(uniqueKey,addedValue);
}
私有CacheItemPolicy CreateItemPolicy()
{
//这将设置从缓存中删除项的时间
var expirationTime=DateTime.Now.AddHours(\u hoursLimit);
var offset=新的DateTimeOffset(expirationTime);
返回新的CacheItemPolicy
{
绝对过期=偏移量
};
}
公共IEnumerable GetLast(整数金额)
{
返回_cache.Select(pair=>(SavedItem)pair.Value)
.OrderBy(项=>item.Timestamp)
.Select(项=>item.Value)
.收取(金额);
}
}
为什么不能同时使用两者?使用Add
方法将它们包装到一个类中,该方法会将给定项添加到both@Fabio:您将必须使用某种锁定机制同步对两个单独集合的访问,但是您也可以使用由锁保护的单个列表,这应该是问题的解决方案。但是,这个问题特别提到了一个并发集合。堆栈将被填满,无法删除旧项。FIFO数据结构总是在开始时有其最早的项。因此,队列中的第一项是最早的,而不是最后一项。要删除超过某个时间跨度的项目,您必须在显示前验证每个已出列的项目,或定期从头到尾删除项目范围。您是否查看过BlockingCollection,它允许生产商发出生产结束的信号@ManuelFaux,您可以使用MemoryCache
删除“到期”项。为了提高性能,我将使用“SkipWhile()”,因为“Where()”会在整个集合中迭代以比较每个项。“ConcurrentBag”是无序的。这需要搜索整个包,通过比较每个包的日期时间来查找最后添加的项目。如果你想使用一个列表或数组,你只需要从末尾获取最新的。现在,您可以使用SkipWhile()在集合中线性移动。和Take()或TakeWhile()不修改源集合。您必须自己删除这些项目,否则备份集将包含过时的数据,并且增长缓慢down@BionicCode,使用另一种方法更新了答案,该方法应处理删除“过期”值的问题。