goo*_*ate 11 c# caching hashtable memorycache concurrentdictionary
我有一个高效的C#应用程序,它在多线程CPU上以每秒5k到10k记录的速率接收80字节的数据.
我现在需要设置一个内存缓存来检测和过滤重复记录,这样我就可以抑制它们在管道中进一步移动.
缓存规格(最大阈值)
题
设置内存缓存,字典,哈希表,数组等的最佳方法是什么,它将允许最有效的查找,清除旧的缓存数据,并防止被击中的数据到期.
我查看了ASP.Net Cache,System.Runtime.MemoryCache,但我认为我需要一些更轻量级的东西来定制以获得正确的吞吐量.我也在看System.Collections.Concurrent作为替代和相关的白皮书.
有没有人对最佳方法有什么建议?
记住,不要过早优化!
在不诉诸非托管代码,指针等的情况下,可能有一种相当简洁的方法.
对我旧的普通笔记本电脑进行快速测试表明,您可以添加1,000,000个条目,HashSet
同时在~100ms内删除100,000个条目.然后,您可以在~60ms内使用相同的1,000,000个值重复该值.这适用于长期工作 - 80字节的数据结构显然更大,但是一个简单的基准测试是有序的.
我的建议:
实现'查找'和'重复检测'作为一个HashSet
,这对于插入,删除和查找非常快.
实现实际缓冲区(接收新事件并使旧事件过期)作为适当大的循环/环形缓冲区.这将避免内存分配和解除分配,并可以在前面添加条目并从后面删除它们.以下是一些有用的链接,包括一个(第二个),它描述了缓存中的项目到期的算法:
请注意,如果您希望缓存受元素数量(例如100,000)而不是事件时间(比如最后5分钟)限制,则循环缓冲区会更好.
当从缓冲区中删除项目(首先从末尾搜索)时,也可以从缓冲区中删除它们HashSet
.无需使两个数据结构相同.
在您需要之前避免多线程!你有一个自然的"连续"工作量.除非您知道某个CPU线程无法处理速度,否则请将其保存在单个线程中.这可以避免争用,锁定,CPU缓存未命中以及其他多线程问题,这些问题往往会减慢非常难以并行的工作负载.我的主要警告是,您可能希望将事件的"接收"卸载到与处理它们不同的线程中.
上述建议是分阶段事件驱动架构(SEDA)背后的主要思想,它被用作高性能和稳定行为事件驱动系统(如消息队列)的基础.
上述设计可以干净地包装,并尝试以最小的复杂性实现所需的原始性能.这仅提供了一个合适的基线,现在可以从中提取和测量效率.
(注意:如果您需要缓存的持久性,请查看Kyoto Cabinet.如果您需要缓存对其他用户可见或分发,请查看Redis.