【发布时间】:2010-12-17 18:13:24
【问题描述】:
我正在尝试优化一个并发集合,以尽量减少读取的锁争用。第一遍是使用链表,它允许我只锁定写入,而许多同时读取可以继续畅通无阻。这使用了自定义 IEnumerator 来产生下一个链接值。一旦我开始将集合上的迭代与普通的 List<T> 进行比较,我注意到我的实现速度大约是原来的一半(对于 1*m* 项目的集合上的 from x in c select x,我得到了 24ms for @ 987654324@ 和 49ms 用于我的收藏)。
所以我想我会使用ReaderWriteLockSlim 并牺牲一点读取争用,这样我就可以使用List<T> 作为我的内部存储。由于我必须在迭代开始时捕获读锁并在完成时释放它,我首先为我的IEnumerable 做了一个屈服模式,foreaching 覆盖了内部List<T>。现在我只得到 66ms。
我查看了 List 的实际作用,它使用了 T[] 的内部存储和自定义的 IEnumerator 来向前移动索引并返回当前索引值。现在,手动使用 T[] 作为存储意味着更多的维护工作,但是,我正在追逐微秒。
但是,即使模仿 IEnumerator 在数组上移动索引,我能做的最好的事情也只有 ~38ms。那么是什么给了List<T> 其秘诀,或者说什么是迭代器的更快实现?
更新:原来我的主要速度罪魁祸首是运行调试编译,而 List<T> 显然是一个发布编译。在发布时,我的实现仍然比List<T> 慢一点,尽管在单声道上它现在更快。
我从朋友那里得到的另一个建议是 BCL 更快,因为它在 GAC 中,因此可以由系统预编译。我必须在 GAC 中进行测试才能验证该理论。
【问题讨论】:
-
@Arne:我添加了一个您可能想尝试的编辑。事实上,如果您不需要检测并发修改,您应该能够击败
List<T>的性能:)
标签: c# performance ienumerable yield ienumerator