【问题标题】:Which collection class to use for a rolling period timeseries of data?哪个集合类用于滚动周期时间序列数据?
【发布时间】:2016-11-01 15:14:19
【问题描述】:

我想实现一个包含时间序列数据的 c# 类 (.NET 4.6.1),如下所示:

  • timeseries 是一个以 DateTime 为键的集合,每个都有一个关联的值(例如一个双精度数组)
  • 积分将严格按时间顺序添加
  • 会有一个滚动时间段 - 例如1 小时 - 添加新点时,开始时超过此时间段的所有点都将被删除
  • 性能的关键问题将是快速添加新点,并找到特定时间的数据点(二分搜索或更好的搜索是必不可少的)。有时集合中会有 100k 的点数。
  • 它必须是线程安全的
  • 它必须具有相对的内存效率 - 例如它不能只保留从一开始的所有点 - 随着时间的推移,内存占用必须相当稳定。

那么就底层集合类而言,什么是好的方法呢?使用列表会很慢——因为滚动周期意味着我们需要从列表的开头删除很多内容。 Queue 或 LinkedList 可以解决这个问题 - 但我不认为它们提供了访问集合中第 n 个项目的快速方法(ElementAt 只是迭代,所以非常慢)。

我能想到的唯一解决方案是将数据存储两次——一次存储在一个易于从一开始就删除的集合中——另一次存储在一个易于搜索的集合中(使用一些糟糕的后台进程来修剪过时的点以某种方式从搜索集合中获取)。

有没有更好的方法来解决这个问题?

谢谢。

【问题讨论】:

  • 为什么List会慢,最后删​​除项目应该是O(1)
  • 但是要修剪陈旧的数据,我必须从列表的开头删除项目 - 我认为当列表很大时这会很慢。
  • 我的错 - 这是 O(Count) 而不是 O(count) :-)
  • 您可能想查看SortedList<TKey, TValue>,您只需要在每次读取或写入访问时用ReaderWriterLockSlim 将其包装起来,以使其线程安全。
  • SortedList 的问题在于它从列表开头删除项目也很慢 - 即它的 O(n) - 当集合中有 100k+ 个项目时非常慢。

标签: c# performance collections time-series


【解决方案1】:

当我第一次看到这个问题时,我立即想到了队列,但正如您所发现的,大多数内置队列并不能有效地允许索引访问。

我能想到的最佳建议是使用 ConcurrentDictionary。线程安全,按键接近恒定的访问时间,您可以直接键入 DateTimes 等。这是您在功能上所需的一切,除了管理大小/时间线的行为。为此,您使用一点 Linq 来扫描 Keys 属性以查找比添加的最新键早一小时以上的键,然后 TryRemove() 每个键(您可以从 ConcurrentDictionary 派生并覆盖 TryAdd() 以在以下情况下自动执行此操作添加任何新内容)。

唯一的其他潜在问题是它的内存效率不是很高; .NET 字典的基于 HashSet 的实现需要一个二维数组来根据键的哈希值进行存储,即使集合中有 100k 项,该数组也将被稀疏填充。

【讨论】:

  • 感谢您的快速回复 - 我会试试 ConcurrentDictionary。我可能不得不保留一个单独的键集合——因为我还希望能够查找不精确的键值并返回以前的值。不过这会比我之前的想法好很多。
  • Dictionary 中的 Keys 集合本质上是一个 ReadOnlyCollection;您可以对其进行 Linq 查询和其他基于列表的读取操作,包括查找小于示例时间戳的最大键值。它是线程安全的,但要做到这一点,他们必须克隆实际 Dictionary 的键数组,因此如果您在其他线程中不断插入和删除键,则对预期键值的“边缘”进行的操作可能不可靠。
  • 我认为在字典上引用键会涉及每次从头开始创建一个新的键集合?如果不是这将是完美的。你能确认这不是它的作用吗?
  • 这基本上就是它的作用; Keys 属性返回通过克隆基础 Dictionary 的 Keys 属性生成的ICollection<TKey>。这是使此操作线程安全的最快和最简单的方法。为了想出更好的东西,您必须实现一个锁定系统,该系统允许就地对集合进行多次枚举,但会阻止对每个元素的并发访问。当不同的线程以不同的速度或不同的顺序枚举集合时,这将不可避免地产生死锁,您必须检测和解决。
  • 如果你真的需要做所有这些,我建议你使用数据库引擎; SQLite 或仅仅是 SQL Server Express 的一个实例将比您在下一周的开发中想出的任何东西都更加高效和并发容忍。编写一个简单的类来执行您需要的任务,该类将与 SQL 引擎交互以执行这些操作,然后您就完成了。
猜你喜欢
  • 1970-01-01
  • 2011-02-25
  • 2020-01-23
  • 2016-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
相关资源
最近更新 更多