我正在消耗一系列半随机令牌。对于每个令牌,我都要维护大量数据(包括一些子集合)。
唯一令牌的数量是无限制的,但实际上往往大约为100,000-300,000。
我从列表开始,使用Linq查询确定要更新的相应令牌对象。
$_POST["display_File_count"]
在第一个~30k的独特令牌中,我能够找到并更新〜1,100个令牌/秒。
性能分析表明,public class Model {
public List<State> States { get; set; }
...
}
var match = model.States.Where(x => x.Condition == stateText).SingleOrDefault();
花费了85%的总Cpu周期(这是有道理的,列表是低效的搜索方式)。
所以,我将列表切换到HashSet并再次进行分析,确信HashSet能够随机搜索更快。这一次,我只处理~900令牌/秒。 Linq(89%)花了几乎相同的时间。
所以......首先,我是否在滥用Where(...).SingleOrDefault()
? (使用Linq是强制转换为IEnumerable,然后是枚举/类似的东西?)
如果没有,那么自己实施的最佳模式是什么?我的印象是HashSet已经进行了二元搜索,所以我假设我需要构建某种树结构并且有更小的子集?
回答一些问题形式的评论...条件是唯一的(如果我得到相同的标记两次,我想更新相同的条目),HashSet是股票.Net实现(HashSet
)。
更广泛的代码视图是......
System.Collections.Generic.HashSet<T>
答案 0 :(得分:6)
var match = model.States.Where(x => x.Condition == stateText).SingleOrDefault();
如果你使用哈希集做同样的事情,那就没有节省。散列集经过优化,可以快速回答“这个集合中的成员是谁?”不是“是否有成员在集合中使这个谓词成立?”后者是线性时间,无论是哈希集还是列表。
满足您需求的可能数据结构:
创建一个从文本到状态的字典映射,然后在文本键的字典中搜索以获得结果状态。这是理论上搜索和插入的O(1);在实践中,它取决于哈希的质量。
创建从文本到状态的排序字典映射。再次,搜索文本。排序的字典使密钥在平衡树中排序,因此用于搜索和插入的是O(log n)。
答案 1 :(得分:1)
30k并不是那么多,所以如果状态是独特的,你可以做这样的事情。 字典访问速度要快得多。
var statesDic = model.States.ToDictionary(x => x.Condition, x => x);
var match = statesDic.ConstainsKey(stateText) ? statesDic[stateText] : default(State);
引用MSDN:
Dictionary泛型类提供从一组键到一组值的映射。字典的每个添加都包含一个值及其关联的键。通过使用其键来检索值非常快,接近于O(1),因为Dictionary类是作为哈希表实现的。
您可以找到有关词典here的更多信息。 还要注意字典使用内存空间来提高性能,你可以快速测试300k项目,看看我说的是什么样的空间:
var memoryBeforeDic = GC.GetTotalMemory(true);
var dic = new Dictionary<string,object>(300000);
var memoryAfterDic = GC.GetTotalMemory(true);
Console.WriteLine("Memory: {0}", memoryAfterDic - memoryBeforeDic);