我在另一个代码中看到过第二个,我想这个长度比较是为了提高代码生产力。它被用于具有特定字典的脚本语言的解析器中:单词长度为 4 到 24 个字母,平均为 7-8 个字母,字母表包括 26 个拉丁字母加上"@","$"和"_"。
长度比较用于转义 == 运算符处理 STL 字符串,这显然比简单的整数比较花费更多时间。但同时,给定字典中的第一个字母分布只是比单词大小的分布更宽,因此比较字符串的两个首字母通常比该字符串的大小更常见。这使得长度比较变得没有必要。
我运行了一些测试,这就是我发现的:在测试两个随机字符串比较百万次时,第二种方式要快得多,因此长度比较似乎很有帮助。但是在工作项目中,它在调试模式下的工作速度甚至更慢,而在发布模式下则不够快。
所以,我的问题是:为什么长度比较可以加快比较速度,为什么它可以减慢比较速度?
UPD:我也不喜欢第二种方式,但我想这样做是有原因的,我想知道,这个原因是什么。
UPD2:说真的,问题不在于如何做到最好。在这种情况下,我什至不再使用 STL 字符串了。难怪长度比较是不必要的和错误的等。奇迹是 - 它确实倾向于在某个测试中稍微好一点。这怎么可能?
如果很重要,假设你的库已经做到了。不要为了微优化而以这种方式弄乱你的代码,除非它真的很重要。
短路什么时候会有益
短路优化仅在以下情况下有用:
- 与完整测试的成本相比,比较成本较低
- 比较通常会导致短路
在数学上,设 S 是短路条件的成本,F 是完全条件的成本,P 是发生短路的情况的百分比(不需要完全条件)。
原装外壳(无短路)的平均成本为F
短路优化的平均成本为 S + F * (1-P)
因此,如果优化有任何好处,则必须应用以下内容:
S + F * (1-P)
即
S <F*P>
字符串比较成本
你进一步写道:
这显然比简单的整数比较需要更多的时间。
这根本不明显。字符串比较在找到第一个差异时终止,因此,根据您处理的字符串,在绝大多数情况下,它可能会在第一个或第二个字符上终止。此外,只要两个字符串中都有足够的数据,甚至可以通过首先比较 DWORDS(一次 4 个字符)来优化比较。
您的案例
随机测试数据和脚本解析之间的主要区别在于真实数据远非随机。解析器很可能是确定性的,一旦匹配,它就不会再比较了。甚至脚本数据也不是随机的 - 某些关键字可能比其他关键字使用得更多。如果解析器以首先检查最常用的关键字的方式构造,则可能需要进行大量比较才能完成,因为在字符串匹配时始终需要进行完全比较。
一般来说,你应该把这个问题留给STL,而不必担心它。
但是,如果这是一个您需要优化的区域(我严重怀疑),并且如果您了解字符串的字母分布/长度分布,则可以从字符串中派生一个新类,并重载 == 运算符以最有效的方式为您的应用程序执行相等性测试。(长度在前,第一个字符在前,向前,向后,随便什么)。
这比将"优化"分散在整个代码中要好。
在您的随机测试中,字符串可能已经足够长以显示增益,而在实际情况下,您可能会处理较短的字符串,并且两个比较的常数因子不会被不执行测试的字符串比较部分的任何增益所抵消。
std::string 运算符== 的实现无法知道先检查长度还是开始检查字符会更快。显然,对于相同长度的字符串来说,检查长度是一种浪费。因此,STL 的不同实现可能会有不同的性能。
仅将显式长度检查作为最终优化(明确注释),并且仅当探查器确认其优势时
长度比较对我来说没有任何意义..使用比较运算符就足够
触发STL的实现。 这应该没关系
长度比较是为了尝试一些短路优化。
我假设长度比较比完整字符串比较更快,所以如果这可以消除 99% 的不匹配,它将比每次进行完整字符串比较更快。
代码将执行长度比较,它将失败,然后它将忽略完整的字符串比较并跳过代码。
std::string 的长度很可能是 std::string 对象的成员。相比之下,第一个字符很可能在堆上。这意味着比较字符串长度可以提高引用的位置。当然,随着短字符串优化,这变得更加复杂 - Lhs[0]
可能在堆上,而Rhs[0]
在堆栈上。