下午好,
我正在编写一个简单的词法分析器,它基本上是this one的修改版本。获取每个令牌后,我需要执行轻微的修改并重新分析它以重新检查它的类型。当然,在词法分析之后,我需要重新使用整个令牌列表来对其进行一种“解析”。我的问题是,如果在词法分析器中使用IEnumerable<Token>
和yield return
语句会使整个程序的性能变慢...是否最好使用List<Token>
来迭代地构建列表并使用一个正常的return
陈述?如何迭代IEnumerable
/ List
?哪一个更快?
非常感谢。
答案 0 :(得分:5)
你问的是错误的问题,你应该更担心正则表达式的成本。枚举令牌只是其中的一小部分,优化代码的速度可能只有两倍,但只能将程序性能提高1%。
编写代码,对其进行概要分析,您将知道如何为版本2执行操作。鉴于这些工具在“人工时间”运行(当程序需要20毫秒时,程序需要两倍的时间内没有明显差异) ,最有可能的结果是“什么都不需要”。
答案 1 :(得分:3)
它可能会对某些性能产生影响 - 但它也允许延迟构建迭代器。
就个人而言,我会以最易读的方式编写代码并测量其性能 - 然后开始担心微观优化这种事情。以一种方式测试,以另一种方式测试,通过使用性能最佳的解决方案,以及实际获得的速度,看看您丢失了多少可读性(如果有的话)。
请注意,迭代一个已知为List<T>
类型的表达式,而不是IEnumerable<T>
上的List<T>
迭代,这可能会带来非常轻微的性能优势,正好由List<T>
实现,如{{1}}使用可变结构实现迭代器本身...如果使用更高的抽象层,基本上你最终会得到一个盒装值,但在那种特殊情况下,我几乎当然更喜欢使用正确的抽象而不是微小的性能改进。
答案 2 :(得分:1)
IEnumerable和yield return语句被转换为GetEnumator()和IL代码中枚举器的实现。
虽然收益率回报在为每个返回的令牌做一些额外工作方面有其优点 在枚举期间,我会坚持创建List并返回列表,因为它会导致更少的方法调用,因此应该更快。
答案 3 :(得分:0)
到目前为止,我确定你会发现你过早地尝试进行优化,根据许多人的说法the root of all evil.
但是,如果你真的想加快速度,那么正则表达式似乎是一种昂贵的方法。每次执行Regex.Match()时,您都会再次扫描字符串,这至少会产生与令牌一样多的扫描。
如果您知道定义令牌的边界(例如,&#39; {&#39;和&#39;}&#39;),您可以扫描字符串一次以构建可枚举的令牌(有了收益或列表,我不认为会有很大的不同)。然后调用者可以重建字符串,查找值以用。替换标记。
当然,这只适用于简单的搜索和替换&#34;类型代币。更复杂的需要更复杂的东西,比如正则表达式。也许您可以扩展TokenDefinition以指定匹配是简单匹配还是正则规则匹配。这将减少执行的正则表达式的数量,但仍保持所需的灵活性。