目录与datetime+字符串键,并自动删除旧的条目

本文关键字:删除 datetime+ 字符串 | 更新日期: 2023-09-27 18:11:46

我有一个应用程序,它接收某些"事件",由一个12个字符的字符串和一个日期时间唯一标识。每个事件都关联一个字符串结果。我需要将这些事件保存在内存中(例如最多8小时),并且能够在我第二次收到相同事件的情况下,能够知道我已经收到了它(在过去的8小时内)。要存储的事件将少于1000个。我不能使用外部存储,必须在内存中完成。

我的想法是使用Dictionary,其中键是由字符串和日期时间组成的类,值是结果。

编辑:字符串本身(实际上是MAC地址)并不能唯一地标识事件,它是MAC和DateTime,这两个组合是唯一的,这就是为什么键必须由两者组成。应用程序是一个从客户端接收特定事件的服务器:该事件在客户端上由客户端MAC和客户端日期时间(不能使用guid)标记。客户端可能会重传相同的数据,通过检查字典中的MAC/Datetime键,我就知道我已经收到了该数据。

然后,每隔一小时(例如),我可以遍历整个集合并删除datetime大于8小时的所有键。

你能建议一个更好的方法来解决这个问题或我选择的数据格式吗?在性能和代码整洁方面。或者使用更好的方法来删除旧数据,例如使用LINQ。

谢谢,Mattia

目录与datetime+字符串键,并自动删除旧的条目

事件时间必须而不是是键的一部分——如果是,您如何能够告诉您已经收到了这个事件?因此,您应该转向一个字典,其中键是事件名称,值是日期和结果的元组。

有时你可以使用LINQ:

从字典中删除旧数据。
dictionary = dictionary
    .Where(p => p.Value.DateOfEvent >= DateTime.Now.AddHours(-8))
    .ToDictionary();

如果需求声明每小时更新一次就足够了,并且字典中的条目永远不会超过1000个,那么您的解决方案应该是完全足够的,并且可能是其他查看您代码的人最容易理解的。我可能会推荐不可变的结构来代替类,但就是这样。

如果立即删除而不是每小时删除一次有好处,你可以做一些事情,你也可以添加一个计时器,在8小时后删除它,但你必须处理线程安全并清理所有计时器等。可能不值得。

我会避免OrderedDictionary方法,因为它的代码更多,并且可能会更慢,因为它必须在每次插入时重新排序。

这是一个常见的咒语,首先关注保持代码简单,只在必要时优化。除非您有一个已知的瓶颈并对其进行分析,否则您永远不会知道您的优化是否正确。(从你的描述中,没有分析就无法告诉你哪个部分是最慢的)。

我会选一本字典

这样你可以非常快速地搜索字符串(O(1)-operation)。

其他集合较慢:

  • OrderedDictionary:是缓慢的,因为它需要装箱和拆箱。
  • SortedDictionary:执行O(log n)个操作
  • 所有普通数组和列表:使用O(n/2)操作。

一个例子:

public class Event
{
    public Event(string macAddress, DateTime time, string data)
    {
        MacAddress = macAddress;
        Time = time;
        Data = data;
    }
    public string MacAddress { get; set; }
    public DateTime Time { get; set; }
    public string Data { get; set; }
}
public class EventCollection
{
    private readonly Dictionary<Tuple<string, DateTime>, Event> _Events = new Dictionary<Tuple<string, DateTime>, Event>();
    public void Add(Event e)
    {
        _Events.Add(new Tuple<string, DateTime>(e.MacAddress, e.Time), e);
    }
    public IList<Event> GetOldEvents(bool autoRemove)
    {
        DateTime old = DateTime.Now - TimeSpan.FromHours(8);
        List<Event> results = new List<Event>();
        foreach(Event e in _Events.Values)
            if (e.Time < old)
                results.Add(e);
        // Clean up
        if (autoRemove)
            foreach(Event e in results)
                _Events.Remove(new Tuple<string, DateTime>(e.MacAddress, e.Time));
        return results;
    }
}

我将使用OrderedDictionary,其中键是12个字符的标识符,结果和日期时间是值的一部分。遗憾的是OrderedDictionary不是泛型的(键和值都是对象),所以您需要自己进行类型转换和类型检查。当您需要删除旧的事件时,您可以通过OrderedDictionary逐个查找,并在获得足够新的时间时停止。这假定您使用的日期时间在添加到字典时是有序的。