我有一个高效的 C# 应用程序,它在多线程 CPU 上以每秒 5k 到 10k 条记录的速率接收 80 字节的数据。

我现在需要在内存缓存中设置一个来检测和过滤重复记录,这样我就可以抑制它们在管道中进一步传播。

缓存规范(最大阈值)

  • 80 字节数据
  • 10,000 条记录/秒
  • 60 秒缓存 = key 数量 = 60,000
  • (总计 48000000 字节 = 48Mb)
  • 理想缓存大小 = 5 分钟(或 240Mb)
  • 可接受的运行时缓存大小膨胀 = 1 GB

  • 问题

    设置内存缓存、字典、哈希表、数组等的最佳方法是什么,以实现最有效的查找、清除旧缓存数据并防止命中的数据过期。

    我查看了 ASP.Net CacheSystem.Runtime.MemoryCache ,但认为我需要更轻量级和定制的东西来实现正确的吞吐量。我也在寻找 System.Collections.Concurrent 作为替代和 this related whitepaper

    有没有人对最好的方法有什么建议?

    最佳答案

    记住,不要过早地优化!

    可能有一种相当简洁的方式来做到这一点,而无需求助于非托管代码、指针等。

    在我的旧的普通笔记本电脑上进行的快速测试表明,您可以将 1,000,000 个条目添加到 HashSet,同时在大约 100 毫秒内删除 100,000 个条目。然后,您可以在大约 60 毫秒内使用相同的 1,000,000 个值重复该操作。这仅适用于 longs - 80 字节数据结构显然更大,但需要一个简单的基准测试。

    我的建议:

  • 将“查找”和“重复检测”实现为 HashSet ,这对于插入、删除和查找非常快。
  • 将实际缓冲区(接收新事件并过期旧事件)实现为适当大的循环/环形缓冲区。这将避免内存分配和释放,并且可以在前面添加条目并从后面删除它们。以下是一些有用的链接,其中一个(第二个)描述了缓存中过期项目的算法:

  • Circular Buffer for .NET

    Fast calculation of min, max, and average of incoming numbers

    Generic C# RingBuffer

    How would you code an efficient Circular Buffer in Java or C#
  • 请注意,如果您希望缓存受元素数量(例如 100,000)而不是事件时间(例如最后 5 分钟)的限制,则循环缓冲区会更好。
  • 当项目从缓冲区中删除时(从末尾开始搜索),它们也可以从 HashSet 中删除。无需使两个数据结构相同。
  • 在需要之前避免多线程!您有一个自然的“串行”工作负载。除非您知道您的 CPU 线程之一无法处理速度,否则请将其保留在单个线程中。这避免了争用、锁定、CPU 缓存未命中和其他多线程问题,这些问题往往会降低不是 embarrassingly parallel 的工作负载的速度。我在这里的主要警告是,您可能希望将事件的“接收”从处理它们的过程中卸载到不同的线程。
  • 上述建议是 Staged event-driven architecture (SEDA) 背后的主要思想,用作高性能和稳定行为的事件驱动系统(例如消息队列)的基础。

  • 上面的设计可以简洁地包装,并尝试以最小的复杂性实现所需的原始性能。这只提供了一个不错的基线,现在可以从中提取和测量效率。

    ( Note : 如果您需要缓存的持久性,请查看 Kyoto Cabinet 。如果您需要缓存对其他用户可见或已分发,请查看 0x251381124

    关于c# - 需要一个高效的内存缓存,每秒可以处理 4k 到 7k 次查找或写入,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10564181/

    10-16 22:56