简体   繁体   English

JavaScript字符串比较和数字比较一样快吗?

[英]Is JavaScript string comparison just as fast as number comparison?

I'd like to write a little library for JavaScript enums. 我想为JavaScript枚举编写一个小库。 For me to do that, I need to decide how to store the enum values. 对我来说,我需要决定如何存储枚举值。 Therefore, I'd like to use the fastest way when comparing, but I also want something that is debuggable, so I'm torn between using strings or numbers. 因此,我想在比较时使用最快的方法,但我也想要一些可调试的东西,所以我在使用字符串或数字之间徘徊。 I know I could use objects too, but that would be another question 我知道我也可以使用对象,但这将是另一个问题

For example 例如

// I don't want this because when debugging, you'd see just the value 0
var Planets = {Earth:0, Mars:1, Venus: 2}

// I'd prefer this so that Planets.Earth gives me a nice readable value ("Earth")
var Planets = {Earth: 'Earth', Mars: 'Mars'}

But I'm afraid that when I compare them using if (myPlanet === Planet.Earth) , the string comparison could take a lot longer (say if it were in a tight loop). 但我担心当我使用if (myPlanet === Planet.Earth)比较它们时,字符串比较可能需要更长的时间(比如它是否处于紧密循环中)。 This should be the case because http://ecma-international.org/ecma-262/5.1/#sec-11.9.6 says 这应该是这种情况,因为http://ecma-international.org/ecma-262/5.1/#sec-11.9.6

If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); 如果Type(x)是String,则如果x和y完全相同的字符序列(相应位置的长度和字符相同),则返回true; otherwise, return false. 否则,返回false。

But when I wrote a test case, I found that they take the same amount of time http://jsperf.com/string-comparison-versus-number-comparison/2 so it doesn't seem like it's scanning the whole string. 但是当我写一个测试用例时,我发现他们花了相同的时间http://jsperf.com/string-comparison-versus-number-comparison/2所以它似乎不是在扫描整个字符串。

I know this could be a micro optimization, but my question is: is string equality comparison done using pointers and therefore just as fast as number equality comparison? 我知道这可能是一个微优化,但我的问题是:是否使用指针进行字符串相等比较,因此与数字相等比较一样快?

String comparison could be "just as fast" (depending on implementation and values) - or it could be "much slower". 字符串比较可能 “同样快”(取决于实现和值) - 或者它可能“慢得多”。

The ECMAScript specification describes the semantics , not the implementation . ECMAScript规范描述了语义 ,而不是实现 The only way to Know for Certain is to create an applicable performance benchmark on run it on a particular implementation. 知道确定的唯一方法是在特定实现上运行它时创建适用的性能基准。

Trivially, and I expect this is the case 1 , the effects of string interning for a particular implementation are being observed. 平凡的,我希望情况是1 ,正在观察字符串实习特定实现的影响。

That is, all string values (not String Objects) from literals can be trivially interned into a pool such that implIdentityEq("foo", "foo") is true - that is, there need only one string object. 也就是说,来自文字的所有字符串值(不是字符串对象)可以简单地插入到池中,使得implIdentityEq("foo", "foo")为真 - 也就是说,只需要一个字符串对象。 Such interning can be done after constant folding, such that "f" + "oo" -> "foo" - again, per a particular implementation as long as it upholds the ECMAScript semantics. 只要它支持ECMAScript语义,这种内容可以在恒定折叠之后完成,使得"f" + "oo" -> "foo" - 再次,根据特定实现。

If such interning is done, then for implStringEq the first check could be to evaluate implIdentityEq(x,y) and, if true, the comparison is trivially-true and performed in O(1). 如果完成了这样的实习,那么对于implStringEq ,第一个检查可以是评估implIdentityEq(x,y) ,如果为真,则比较非常简单并且在O(1)中执行。 If false, then a normal string character-wise comparison would need to be done which is O(min(n,m)). 如果为false,则需要进行正常的字符串字符比较,即O(min(n,m))。

(Immediate falseness can also be determined with x.length != y.length , but that seems less relevant here.) (立即虚假也可以用x.length != y.length来确定,但这似乎不太重要。)


1 While in the above I argue for string interning being a likely cause, modern JavaScript implementations perform a lot of optimizations - as such, interning is only a small part of the various optimizations and code hoistings that can (and are) done! 1虽然在上面我认为字符串实习是一个可能的原因,现代的JavaScript实现进行了大量的优化-正因为如此,实习是唯一能(并)做了各种优化和代码吊装的一小部分

I've created an "intern breaker" jsperf . 我创造了一个“实习生断路器”jsperf The numbers agree with the hypothesis presented above. 这些数字与上述假设一致。

  1. If a string is interned then comparison is approximate in performance to testing for "identity" - while it is slower than a numeric comparison, this is still much faster than a character-by-character string comparison. 如果字符串被中断,那么比较是性能的近似来测试“身份” - 虽然它比数字比较慢,但这仍然比逐个字符的字符串比较快得多。

  2. Holding the above assertion, IE10 does not appear to consider object-identity for pass-fast string comparisons although it does use a fast-fail length check. 持有上述断言,虽然IE10确实使用快速失败长度检查,但IE10似乎没有考虑传递快速字符串比较的对象标识。

  3. In Chrome and Firefox, two intern'ed strings which are not equal are also compared as quickly as two that are - there is likely a special case for comparing between two different interned strings. 在Chrome和Firefox中,两个不相等的实习字符串也会快速比较两个字符串 - 在两个不同的实习字符串之间进行比较可能有一个特殊情况。

  4. Even for small strings (length = 8), interning can be much faster. 即使对于小弦(长度= 8),实习也可以快得多。 IE10 again shows it doesn't have this "optimization" even though it appears to have an efficient string comparison implementation. IE10再次显示它没有这种“优化”,即使它似乎有一个有效的字符串比较实现。

  5. The string comparison can fail as soon as the first different character is encountered: even comparing long strings of equal length might only compare the first few characters. 甚至比较相同长度的长字符串可能只比前几个字符:字符串比较可以作为第一个不同的字符遇到一旦失败。


  • Do common JavaScript implementations use string interning? 常见的JavaScript实现是否使用字符串实习? (but no references given) (但没有给出参考)

    Yes. 是。 In general any literal string, identifier, or other constant string in JS source is interned. 通常,JS源中的任何文字字符串,标识符或其他常量字符串都是实体。 However implementation details (exactly what is interned for instance) varies, as well as when the interning occurs 然而,实施细节(例如,实际上是实施的内容)会有所不同,以及实施时的实施情况

  • See JS_InternString (FF does have string interning, although where/how the strings are implicitly interened from JavaScript, I know not) 请参阅JS_InternString (FF确实有字符串实习,尽管字符串在哪里/如何与JavaScript隐式交互,我不知道)

There are cases when string comparison can be much slower (comparing dynamically generated strings) 有些情况下,字符串比较可能会慢得多(比较动态生成的字符串)

The following is 77% slower (in chrome and IE) than all the other tests 以下是比所有其他测试慢77%(在chrome和IE中)

var StringEarth = 'Ear' + 'th';
for (var i = 0; i < ITERATIONS; i++) {
  x = StringPlanets.Venus === StringEarth;
}

The flaw in the tests mentioned in the question is the fact that we are testing against literal strings. 问题中提到的测试中的缺陷是我们正在测试文字字符串。 It seems that JavaScript is optimized so that string comparison for string literals is done just by testing a pointer. 似乎JavaScript已经过优化,因此字符串文字的字符串比较只需通过测试指针即可完成。 This can be observed by creating the strings dynamically. 这可以通过动态创建字符串来观察。 My best guess is that strings from the literal string pool are marked so that they can be compared using addresses only. 我最好的猜测是来自文字字符串池的字符串被标记,以便它们可以仅使用地址进行比较。

Note that string comparison seems just as fast in FF even for dynamic strings. 请注意,即使对于动态字符串,字符串比较在FF中也同样快。 Also, that it's just as slow for even literal strings. 而且,即使是文字字符串也一样慢。

Conclusion All browsers behave differently so string comparison may or may not be slower. 结论所有浏览器的行为都不同,因此字符串比较可能会也可能不会慢。

In general, at best String interning (making a string with a given value into a unique reference or a O(1) comparable symbol) is going to take O(n) time, as it can't do that effectively without looking at all the characters involved. 一般来说,最好的字符串实习(将具有给定值的字符串转换为唯一引用或O(1)可比较符号)将花费O(n)时间,因为如果不全部查看它就无法有效地执行此操作涉及的人物。

The question of relative efficiency then amounts to over how many comparisons the interning is going to be amortized. 然后,相对效率的问题相当于实际分摊的实际比较数量。

In the limit, a very clever optimizer can pull out static expressions which build up strings and intern them once. 在极限中,一个非常聪明的优化器可以提取静态表达式,这些表达式构建字符串并实例化一次。

Some of the tests above, use strings which will have been interned in which case the comparison is potentially O(1). 上面的一些测试,使用将被实习的字符串,在这种情况下,比较可能是O(1)。 In the case where enums are based on mapping to integers, it will be O(1) in any implementation. 在枚举基于映射到整数的情况下,在任何实现中它都是O(1)。

The expensive comparison cases arise when at least one of the operands is a truly dynamic string. 当至少一个操作数是真正的动态字符串时,会出现昂贵的比较情况。 In this case it is impossible to compare equality against it in less than O(n). 在这种情况下,不可能在小于O(n)的情况下比较与它的相等性。

As applied to the original question, if the desire is to create something akin to an enum in a different language, the only lookout is to ensure that the interning can is done in only a few places. 应用于原始问题时,如果希望创建类似于不同语言的enum东西,唯一的了望是确保实习可以仅在少数几个地方完成。 As pointed out above, different Browser use different implementations, so that can be tricky, and as pointed out in IE10 maybe impossible. 如上所述,不同的浏览器使用不同的实现,因此可能很棘手,并且如IE10指出的那样可能是不可能的。

Caveat lacking string interning (in which case you need the integer version of the enum implementation give), @JuanMendes' string-based enum implementations will be essentially O(1) if he arranges for the value of the myPlanet variable to be set in O(1) time. 注意缺少字符串实习(在这种情况下你需要enum实现的整数版本),@ JuanMendes基于字符串的枚举实现将基本上是O(1),如果他安排在O中设置myPlanet变量的值(1次。 If that is set using Planets.value where value is an established planet it will be O(1). 如果使用Planets.value设置,其中value是已建立的行星,则它将为O(1)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM