19

基准:http: //jsperf.com/substringing

因此,我正在启动我的第一个基于 HTML5 浏览器的客户端项目。它必须将非常非常大的文本文件解析为一个或多个对象数组。我知道我将如何进行编码;我现在主要关心的是尽可能快地获取解析器代码,我的主要测试平台是 Chrome。然而,在查看子字符串方法之间的差异时(我已经很久很久没有接触过 JavaScript),我注意到与 FireFox 相比,Chrome 中的这个基准测试非常慢。为什么?

我的第一个假设是它与 FireFox 的 JS 引擎处理字符串对象的方式有关,并且对于 FireFox,此操作是简单的指针操作,而对于 Chrome,它实际上是在进行硬拷贝。但是,我不确定为什么 Chrome不会进行指针操作或 FireFox. 有人有一些见识吗?

JSPerf 似乎正在丢弃我的 FireFox 结果,而不是在 BrowserScope 上显示它们。对我来说,我.substr()在 FF4 中获得了 9,568,203 ±1.44% Ops/sec。

编辑:所以我在 Chrome 下方看到了 FF3.5 的性能结果。所以我决定测试我的指针假设。这使我对Substrings 测试进行了第二次修订1,092,718±1.62%,在 FF4 中执行 Ops/sec 与1,195±3.81%Chrome 中的 Ops/sec 相比,速度降低到仅快 1000 倍,但在性能上仍然存在莫名其妙的差异。

后记: 不,我一点也不担心 Internet Explorer。我担心试图提高我的技能并更深入地了解这种语言。

4

2 回答 2

16

在 Spidermonkey(Firefox 中的 JS 引擎)的情况下,substring()调用只是创建一个新的“依赖字符串”:一个字符串对象,它存储一个指向它的子字符串的指针以及开始和结束偏移量。这正是为了substring()快速,并且是给定不可变字符串的明显优化。

至于为什么 V8 不这样做......可能是 V8 正在尝试节省空间:在依赖字符串设置中,如果您保留子字符串但忘记了原始字符串,则原始字符串无法被 GCed,因为substring 正在使用其部分字符串数据。

无论如何,我只是查看了 V8 源代码,看起来他们根本不做任何类型的依赖字符串;不过,评论并没有解释为什么他们不这样做。

[更新,12/2013]:在我给出上述答案几个月后,V8 增加了对依赖字符串的支持,正如 Paul Draper 指出的那样。

于 2011-06-01T01:43:45.130 回答
1

您是否消除了.length基准测试结果中的读数?

我相信 V8 有一些字符串的表示形式:

1. a sequence of ASCII bytes
2. a sequence of UTF-16 code units.
3. a slice of a string (result of substring)
4. a concatenation of two strings.

数字 4 是使字符串+=高效的原因。

我只是在猜测,但如果他们试图将两个字符串指针和一个长度打包到一个小空间中,他们可能无法用指针缓存大长度,因此最终可能会遍历连接的链接列表以计算长度。这当然假设Array.prototype.join从数组部分创建形式 (4) 的字符串。

它确实导致了一个可检验的假设,即使没有缓冲区副本也可以解释差异。

编辑:

我查看了 V8 源代码,StringBuilderConcat是我开始拉取的地方,尤其是runtime.cc.

于 2011-06-01T01:43:16.427 回答