【发布时间】:2015-10-21 12:22:37
【问题描述】:
我们有一个函数通知我们收到了一个特定时间戳的项目。
这样做的目的是等待一个特定的时间戳,我们等待我们收到我们期望的每个项目,然后在我们与所有项目“同步”后进一步推送通知。
目前,我们有一个 Dictionary<DateTime, TimeSlot> 来存储非同步 TimeSlot(TimeSlot = 我们收到的特定时间戳的所有项目的列表)。
//Let's assume that this method is not called concurrently, and only once per "MyItem"
public void HandleItemReceived(DateTime timestamp, MyItem item){
TimeSlot slot;
//_pendingTimeSlot is a Dictionary<DateTime,TimeSlot>
if(!_pendingTimeSlot.TryGetValue(timestamp, out slot)){
slot = new TimeSlot(timestamp);
_pendingTimeSlot.Add(timestamp,slot );
//Sometimes we don't receive all the items for one timestamps, which may leads to some ghost-incomplete TimeSlot
if(_pendingTimeSlot.Count>_capacity){
TimeSlot oldestTimeSlot = _pendingTimeSlot.OrderBy(t=>t.Key).Select(t=>t.Value).First();
_pendingTimeSlot.Remove(oldestTimeSlot.TimeStamp);
//Additional work here to log/handle this case
}
}
slot.HandleItemReceived(item);
if(slot.IsComplete){
PushTimeSlotSyncronized(slot);
_pendingTimeSlot.Remove(slot.TimeStamp);
}
}
对于不同的项目组,我们有多个并行的“同步器”实例。
它工作正常,除了当系统负载很重时,我们有更多不完整的 TimeSlot,并且应用程序使用了更多的 CPU。探查器似乎表明 LINQ 查询的 Compare 花费了很多时间(大部分时间)。所以我试图找到一些结构来保存这些引用(替换字典)
以下是一些指标:
- 我们有几个(可变,但在 10 到 20 之间)这个同步器的实例
- 同步器当前最大容量(
_capacity)为500项 - 两个不同时间戳之间的最短间隔是 100 毫秒(因此每个同步器每秒有 10 个新的字典条目)(大多数情况下更多的是 1 项/秒)
- 对于每个时间戳,我们预计会收到 300-500 个项目。
所以我们将这样做,对于一个同步器,每秒(最坏情况):
- 1 添加
- 500 获取
- 3-5 次排序
我最好的举动是什么?我想到了SortedDictionary 但我没有找到任何文档告诉我如何根据密钥获取第一个元素。
【问题讨论】:
-
我不认为这是基于意见的——算法复杂度是一个可衡量的数量。
-
最好的解决方案是使用 List 而不是 Dictionary。我会按时间顺序将项目添加到列表中,因此无需执行排序。我会检查列表中的最后一项以及要添加的项目,以确保新项目晚于最后一项。如果没有,则从列表末尾向后工作,直到将新项目按顺序放入列表中。
-
_pendingTimeSlot真的是字典吗?我问是因为没有TryGet方法,OrderBy(..).First()的结果应该是'KeyValuePair',而不是 TimeSlot。 -
@IvanStoev 是的,它是一本字典,但我必须对这段代码进行大量简化以获得可读的形式,所以它不是我真正的代码。但是你是对的,调用的是
TryGetValue方法,order by应该选择Value。我会更新的
标签: c# linq dictionary data-structures