【问题标题】:What is the most efficient way to perform (integer) operations in Javascript?在 Javascript 中执行(整数)操作的最有效方法是什么?
【发布时间】:2011-12-06 14:28:12
【问题描述】:

我正在用 Javascript 实现图灵机(将其视为虚拟机)。我正在制定一个尽可能高效地执行计算的例程(这不是项目从一开始就关注的重点)。

是的,除非遇到性能问题,否则我不应该考虑优化。但是我正在做的事情的性质(大多数非平凡的程序都有非常低效的渐近运行时)意味着总会有一些东西可以从优化中获得。我想尽我所能每秒获得尽可能多的指令(​​合理)。

例如,如果我使用 C++ 编程,解决方案就很清楚了。做一些时间安排。 gprof-O3 等。我将研究我希望代码在其上运行的架构,并且可能还会查看正在生成的程序集。

但不能用 javascript 做到这一点。我的第一直觉是将内部循环中的操作减少为数组查找。在我看来,如果解释器能够将 CPU 缓存性能转换为(希望是短的)一系列整数运算,那么我将能够利用 CPU 缓存性能是一个不错的选择。

图灵机非常简单。它实际上是存在的最简单的计算公式(!):它具有有限数量的状态,双向无限磁带,可以在任一方向移动一个单元的磁带头,并且可以读取和写入单个字符到磁带。

一个程序被编码在一个转换函数中,该函数接受一个状态和一个读取的字符,并利用该信息提供要写入的字符、移动头部的方向和新状态。

这是每一步的逻辑:

// states is an array of arrays of triplets and is the transition func
var trans = states[state][alph_index[tape[pos]]]; 
tape[cur_tape_pos] = trans[0]; // write
cur_tape_pos += trans[1]; // move
state = trans[2]; // state update

这个过程发生在一个循环中。我似乎很清楚磁带将是一个数组。我想将值存储(附加)到数组的末尾至少是使用 Javascript 数组的摊销常数时间操作。附加到数组前面也有很好的性能还不太清楚,所以我可能想要使用两个数组,一个向左延伸,一个向右延伸。

问题是,在幼稚的实现中会在内部循环中插入一个条件语句。我不喜欢那样。无论如何,必须已经有条件检查来检查状态是否为停止状态。所以也许它不会那么糟糕。

还有一种潜在的优化可以消除对alph_index 的索引,方法是将索引存储在字母表中,而不是将字母表值本身存储在磁带上。

但主要问题是这个。我还能做些什么来让它更快?有可能让它更快吗?我不知道执行的哪个组件将成为瓶颈(CPU 或 I/O,或其他什么?),我不知道如何才能找到它。使用 Javascript,我也可以使用哈希表,但似乎数组总是会更快。

也许我过早地寻求建议。随着我的进步,我会回来编辑性能数据。

作为对阅读我的问题的奖励,我将提供一个链接,指向我的项目的实时正在进行的版本:http://stevenlu.net/tm.html

到目前为止,它的操作是操纵一个充满spansdiv,它代表磁带。它还对字符串执行大量操作,并且还对元素进行大量复制,这在涉及图灵机的实际计算时是完全不必要的。但即便如此,它也取得了不错的表现。在我的机器上花了大约一分钟来计算 600,000 步左右 (5^4 = 625),即每秒 10,000 步。这还不错,但我知道我可以通过一些较低级别的编程实现每秒超过一百万。

查看上一代 CPU 的 benchmark perf here,我看到每个内核大约 10,000 MIPS。因此,我估计,如果我可以在运行 50 次 Dhrystone 迭代的时间内运行一次内部循环(即使我不知道这些综合基准实际上做了什么,这对于简单的 C 实现来说似乎很有可能),除非内存带宽限制,我在一个线程上每秒有 2 亿次迭代。我的 600k 步计算将在 3ms 内完成!!

好吧,如果我可以让我的 5^4 计算在浏览器不向我报告它已挂起的情况下运行,我会很高兴...

更新

随着算法的更高效的 javascript 实现完成,9^4 = 6561 的计算需要 58202209 步,计算时间为 6173 毫秒。那是每秒 940 万步。比我原来的 DOM 依赖方法增加了近 1,000 倍。

最初的5^4 计算(即使不滚动磁带也需要大约 30 秒)现在在 84 毫秒内完成。

【问题讨论】:

  • 我喜欢 DOM 图灵机 :)
  • 谢谢 :) 我已经投入了很多工作,我喜欢用 javascript 编程。看看我的俄罗斯方块游戏stevenlu.net/tetris.html
  • 为什么不能分析 JavaScript?如果您在浏览器中运行它,Chrome 会内置它。 Ctrl-shift-C,点击 Profiles,然后开始 CPU profiling...
  • @BobG,很高兴知道。虽然我试过了,但它并没有显示很多有用的信息:主要是100% for (program)
  • 嗯,对于 CS 学生来说,这绝对是一个很酷的玩具。我喜欢滚动磁带!

标签: javascript arrays performance optimization


【解决方案1】:

使用 Javascript,我也可以使用哈希表,但似乎 like 数组总是会更快。

你可能认为 JavaScript 中的“数组”查找是这样工作的:

[ 1, 2, 3, 4, 5 ]
|------>x

给定索引 2,您只需计算:

int operator[] (int index) {
  return start_of_data + (sizeof(data_item) * index);
}

这样您的查找将简单地获得O(1) 时间。

至少在传统上,在 JavaScript 中并非如此。通常,“数组”是带有数字键的哈希映射。因此,每次您进行查找时,您实际上是通过哈希函数运行索引(仅被视为键)。所以,这个:

a[1]

更像是:

a["1"]

这个,并且您正在运行一些(可能相当不错的)哈希函数来尝试使桶分布有规律并最大限度地减少冲突。这对我来说听起来很昂贵,但我不知道优化的实现如何(因为哈希映射查找是摊销的常数时间,但它可能仍然没有那么有效,并且取决于您遇到多少冲突以及遇到时您会做什么一)。

幸运的是,一些(如果不是大多数)现代 JavaScript 解释器在跟踪您的代码以查看您是否像使用稀疏或密集数组一样使用它之后,了解如何使用密集和稀疏集合。仔细检查您期望使用的环境。

我还能做些什么来让它更快?是吗 有可能让它更快吗?

我的一个想法是使用typed arrays 有更好的机会获得恒定的时间查找速度。这有助于 Fabrice Bellard 将整个 Linux 内核移植到 JavaScript / 浏览器 (jslinux.org)。

例如,如果我使用 C++ 编程,解决方案就很清楚了。做一些时间安排。

如果你打算在浏览器中运行东西(看起来你确实这样做了),我建议使用 jsperf.com,因为它们有一个非常好的 Java 计时器(比 JavaScript、IIRC 中处理时间的任何东西更细粒度)或只需使用node.jsRhino 和其他命令行分析工具(如果你真的需要的话,你可以在这个环境中模拟一个DOM……)。

【讨论】:

  • 当我点击 jslinux 的链接时,我差点从座位上跳起来。史诗!
  • 类型化数组看起来像是每次都避免哈希查找的门票,但它似乎更适合大块图像数据和类似的应用程序。也没有 IE9 或 Opera 或 Android 支持。但我会调查一下。
  • IE9 执行我所说的智能输入(用于密集数组)。不确定 Opera 或 JSc(JavaScript 核心,他们可能在 Android 上使用什么)。只是让你知道。
  • 我以为 jsc 是苹果的东西?我真的希望他们有 v8 在 android 上运行。但它看起来不像,因为 android 上的 chrome 仍然很慢
【解决方案2】:

如果你想同时拥有 +ve 和 -ve 整数索引,为什么不使用普通对象呢?您是否使用任何特殊的数组方法?数组方法大多是通用的,因此可以使用其他本机对象调用(可能不适用于宿主对象,但我认为这不是问题)。

在 javascript 中,数组只是对象,所以我不明白为什么访问 array[i] 应该比 object[i] 更快或更慢(当然它可能在不同的实现上)。您只需要保留自己的长度属性(可能是正数和负数)。

如果您提供一些示例代码,无论性能如何,您可能会得到一些更具体的建议。

【讨论】:

  • +1 如果您不使用 push()pop() 并且您永远不需要 length 属性,那么您不需要数组。
  • 嗯。令人失望的是我无法绕过那个哈希步骤。
  • 虽然这确实意味着我可以通过将负值索引到“数组”中来利用它。
  • 您可以通过使用偏移量来模拟数组中的负值 - 使其成为数组的属性。例如。偏移值 10000 表示索引 10001 为 1,而 9999 为 -1。
猜你喜欢
  • 2021-07-24
  • 1970-01-01
  • 1970-01-01
  • 2013-02-10
  • 1970-01-01
  • 2012-10-02
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多