【问题标题】:Performance of bitwise operators in javascriptjavascript中按位运算符的性能
【发布时间】:2009-10-06 00:29:41
【问题描述】:

在 C++/java/C# 等语言中使用位运算符的主要思想之一是它们的速度非常快。但是我听说在 javascript 中它们非常慢(诚然,今天几毫秒可能并不重要)。为什么会这样?

this question 讨论了何时使用位运算符,所以我将这个问题的重点转移到性能上。)

【问题讨论】:

  • 按位运算,在现代编译器开发的这一点上,并不是“非常快”,如果你的意思是 i
  • @Jimmy:现代编译器的先进程度无关紧要,30 年前的编译器足够聪明,知道 i

标签: javascript bitwise-operators


【解决方案1】:

这是一个相当老的问题,但似乎没有人回答更新版本。

C/C++ 中不存在的 JavaScript 对性能的影响是将 floating point 表示(JavaScript 如何存储其所有数字)转换为 32 位整数以执行位操作并返回。

【讨论】:

  • 这不再是真的了,考虑到大多数 JS JIT 完全可以保留一个整数,如果没有对它做任何保证浮点操作的事情。虽然规范要求进行转换,但只要最终结果相同,实际实现就不必这样工作。
  • 有效点,但这仍然适用于所提出的问题。
【解决方案2】:

没有人再使用十六进制了吗?

function hextoRgb(c) {
    c = '0x' + c.substring(1);
    return [(c >> 16) & 255, (c >> 8) & 255, c & 255]; 
}

var c1 = hextoRgb('#191970');
alert('rgb(' + c1.join(',') + ')');

【讨论】:

  • 实际上转移字符串对我来说有点奇怪。但另一方面,它比return /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i.exec(c).slice(1).map(function(e) {return parseInt(e, 16);}); 更容易阅读。
  • @Robert - 它可能看起来很奇怪,但它会比你建议的函数快得多,因为你有一个正则表达式、循环和闭包
【解决方案3】:

我在 JS 中使用零位移位来执行快速整数截断:

var i=3.141532;
var iTrunc=i>>0; //3

【讨论】:

  • 移位操作符的用法实在令人厌恶。
  • 是的,它很脏,我知道,但实际上,它在 Flash 游戏编程中占有一席之地。在 AVM1 的日子里,这是最快的方式。不知道这是否适用于 JS。
  • var iTrunc = i|0;为您节省一杆高尔夫(在此处的一些代码高尔夫线程上看到了这一点)
  • +1 编程就是要确保程序员和计算机理解你所做的事情,如果满足这些条件,习语就非常合适。所有语言都有它们,甚至是英语。习语一开始可能不熟悉,但只要它们 (1) 易于记忆和 (2) 可识别,它们就完全适合程序员的词典。
  • 我认为你需要了解这是游戏编程,这种事情既常见又需要。不过,拥有解释项目性能策略的优秀文档是个好主意。您应该看到在 JVM 中最小化垃圾收集所需的一些箍。
【解决方案4】:

您想在什么时候使用它们?当您想要进行按位运算时,您会想要使用它们。就像您使用布尔运算符进行布尔运算,使用数学运算符进行数学运算一样。

如果您对位运算符感到满意,那么将它们用于某些应用程序是很自然的。除了过度优化的布尔数组之外,它们还可以用于许多目的。当然,这些情况在 Javascript 编程中并不经常出现,但这并不是运算符不可用的原因。

【讨论】:

    【解决方案5】:

    我找到了一些很好的信息@ http://dreaminginjavascript.wordpress.com/2009/02/09/bitwise-byte-foolish/

    显然他们这些天的表现非常好。你为什么要使用它们?与其他任何地方的原因相同。

    【讨论】:

    • 我迟到了 3 年,但感谢您链接好读 =)
    • @aschyiel 好吧,我迟到了 10 年……派对还在继续吗?
    【解决方案6】:

    有一个用 JavaScript 编写的NES emulator - 它似乎大量使用了位运算。

    【讨论】:

      【解决方案7】:

      我认为让运营商高效或低效取决于实施者。例如,没有什么可以阻止 JavaScript 实现者制作 JITting VM,它将按位操作转换为 1 条机器指令。因此,“JavaScript 中的位运算符”固有并不慢。

      【讨论】:

      • @Snarfblam 这种改进 javascript 实现的“理论”在 javascript 的短暂历史中具有许多实际的先例。另外,我不确定这也是 e.e.coli 的观点,CPU 都支持快速按位运算,因此在这个低级别上,按位运算确实没有什么固有的慢,所以如果由于某种原因 javascript 实现草率地失败了将 js 按位操作映射到这些高效的机器操作,如果有任何迹象表明这个问题是大多数 js 使用的瓶颈,这可以很容易地修复,并且更快。
      【解决方案8】:

      我怀疑按位运算在 javascript 中特别慢。由于此类操作可以直接映射到 CPU 操作,这些操作本身非常高效,似乎没有任何按位操作的固有特征会迫使它们在 javascript 中变得不可挽回地变慢
      2015 年 12 月编辑:我的立场是正确的! Javascript 在按位运算方面遭受的性能损失来自需要从浮点数转换为 int 并返回(因为 Javascript 中的所有数字变量都存储为浮点值)。感谢 Chad Schouggins 指出这一点。

      尽管如此,正如在几个回复中所指出的那样,存在各种依赖于按位运算的 javascript 应用程序(例如:密码学和图形学)并且不是特别慢......(请参阅此页面上的 Silky 和 ​​Snarfblam)。这表明,虽然比 C/C++ 和其他将按位运算直接转换为单个本地 CPU 指令的语言要慢,但按位运算却很慢。

      让我们永远不要考虑以下可能性,即某些特定原因导致 javascript 主机的各种实现者以一种使这些操作极其缓慢的方式实现按位操作,并看看这是否重要...

      虽然 javascript 已用于其他目的,但 在提供用户界面类型的服务方面最常用这种语言
      顺便说一句,我根本没有任何贬义的意思。执行这些智能 UI 功能,并考虑对语言施加的各种限制以及对标准的松散遵守,需要 - 并且一直需要 - 有才华的 javascript 黑客。
      关键是,在 UI 类型要求的上下文中,需要任何数量的位操作,这些操作可能会暴露 javascript 在处理此类操作时的缓慢性,这种情况充其量是不常见的。因此,对于典型用途,程序员应该使用按位运算,如果这种方法似乎可以很好地处理整个程序/数据,并且他们应该在不关心性能问题的情况下这样做。在不太可能的性能情况下按位使用产生的瓶颈,总是可以重构的,但最好还是在早期优化中保持清晰。

      上述值得注意的例外是canvas的引入,在现代浏览器上,我们可以预期javascript主机将需要更原始的图形功能,并且在某些情况下可能需要这样的操作大量的按位运算(以及健康的数学函数)。这些服务很可能最终会通过 javascript 库得到支持(甚至最终作为语言添加)。对于这样的图书馆,行业的共同智慧将被用来找出最有效的方法。此外,如果确实存在按位运算的 javascript 性能弱点,我们会得到一些帮助,因为我预测将修改各种主机(浏览器)上的 javascript 实现以改进这个特定区域. (这将遵循我们多年来看到的典型的 javascript 演变模式。)

      【讨论】:

        【解决方案9】:

        人们在 JavaScript 中做有趣的事情。

        例如,其中实现了很多密码算法(出于各种原因);所以当然要使用位运算符。

        【讨论】:

          【解决方案10】:

          在其 Windows Scripting Host JScript 化身中使用 JavaScript,您可能有理由使用按位运算符来挑选从 WMI 或 Active Directory 调用返回的值中的标志。例如,AD 中用户记录的 User Access 值包含多个标志,封装在一个长整数中。

          ADS_UF_ACCOUNTDISABLE = 0x00000002;
          
          if (uac & ADS_UF_ACCOUNTDISABLE == ADS_UF_ACCOUNTDISABLE) {
            // user account has been disabled
          }
          

          或者某人的任意表结构可能包含这样一个字段,可以通过 ADO 和 JScript 访问。

          或者您可能希望在任何平台上将一些检索到的数据转换为二进制表示,只是因为:

          BinaryData = "L";
          BinaryString = BinToStr(BinaryData, ".", "x");
          
          // BinaryString => '.x..xx..'
          

          因此,人们可能想在 JavaScript 中进行位操作的原因有很多。至于性能,唯一知道的方法就是编写它并测试它。我怀疑在大多数情况下它是完全可以接受的,不会比这些系统所包含的众多低效率中的任何其他情况更糟糕。

          【讨论】:

            【解决方案11】:

            当速度至关重要时,您可以将它们用于位掩码:http://snook.ca/archives/javascript/storing_values/

            另外,如果您需要支持 Netscape 4,您可以使用它们来处理 Document.captureEvents()。并不是说任何受人尊敬的公司都会让你为 NS4 编写 JS...

            【讨论】:

            • 欢迎来到地狱。永恒的苦难有两种选择:在木炭烤架上燃烧,或为 NS4 编写 JS。
            【解决方案12】:

            这里正在对许多按位运算进行基准测试:http://jsperf.com/rounding-numbers-down/3

            不过,您可以随意在 jsPerf 上创建自己的性能测试用例!

            【讨论】:

              猜你喜欢
              • 2016-04-12
              • 1970-01-01
              • 2014-04-08
              • 2012-09-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-04
              相关资源
              最近更新 更多