【发布时间】:2016-06-06 00:37:39
【问题描述】:
我正在使用半随机令牌流。对于每个令牌,我都维护了大量数据(包括一些子集合)。
唯一令牌的数量是无限的,但实际上往往在 100,000-300,000 左右。
我从一个列表开始,并使用 Linq 查询确定了要更新的适当令牌对象。
public class Model {
public List<State> States { get; set; }
...
}
var match = model.States.Where(x => x.Condition == stateText).SingleOrDefault();
在前约 3 万个唯一令牌中,我能够找到并更新约 1,100 个令牌/秒。
性能分析表明,总 Cpu 周期的 85% 都花在了 Where(...).SingleOrDefault() 上(这是有道理的,列表是一种低效的搜索方式)。
因此,我将列表切换到 HashSet 并再次进行分析,确信 HashSet 能够更快地随机搜索。这一次,我每秒只处理约 900 个令牌。在 Linq 上花费的时间几乎相同 (89%)。
所以...首先,我是否误用了HashSet? (使用 Linq 是否强制转换为 IEnumerable,然后是枚举/类似的东西?)
如果不是,实现自己的最佳模式是什么?我的印象是 HashSet 已经进行了二进制搜索,所以我认为我需要构建某种树结构并拥有更小的子集?
回答 cmets 的一些问题...条件是唯一的(如果我两次获得相同的令牌,我想更新相同的条目),HashSet 是股票 .Net 实现 (System.Collections.Generic.HashSet<T>)。
更广泛的代码视图是......
var state = new RollingList(model.StateDepth); // Tracks last n items and drops older ones. (Basically an array and an index that wraps around
var tokens = tokeniser.Tokenise(contents); // Iterator
foreach (var token in tokens) {
var stateText = StateToString(ref state);
var match = model.States.Where(x => x.Condition == stateText).FirstOrDefault();
// ... update the match as appropriate for the token
}
【问题讨论】:
-
x.Condition 是唯一的吗?
-
那么你的 HashSet 实现在哪里呢?
-
如果您确实想对
T的实例执行集合操作,那么您可以从使用HashSet<T>中受益,但当您必须遍历所有项目以检查 T- 的某个属性时则不然实例具有一定的价值。如果您想要快速查找,您应该使用字典,其中使用Condition属性作为键。 -
显示您希望我们评论的代码。
-
哈希集不进行二分查找。他们使用哈希算法。因此得名。
标签: c# performance search collections random-access