【问题标题】:How using BigDecimal would affect application performance?使用 BigDecimal 会如何影响应用程序的性能?
【发布时间】:2010-11-25 13:40:32
【问题描述】:

我想在每秒包含数千个订单和执行报告的低延迟交易应用程序中使用 BigDecimal 来表示任意精度数字,例如价格和金额。

我不会对它们进行很多数学运算,因此问题不在于 BigDecimal 本身的性能,而在于 BigDecimal 对象的大容量会影响应用程序的性能。

我担心的是,大量的短期 BigDecimal 对象会给 GC 带来压力,并导致 CMS 收集器中出现更大的 Stop-The-World 停顿 - 这绝对是我想要避免的。

您能否确认我的担忧并提出使用 BigD 的替代方案?另外,如果您认为我的担忧是错误的,请解释原因。

更新

感谢所有回答的人。我现在确信使用 BigDecimal 会降低我的应用程序的延迟(尽管我仍打算对其进行测量)。

暂时我们决定坚持使用“非常非 OOP”的解决方案(但不会影响准确性) - 使用两个 ints,一个用于尾数,另一个用于指数。这背后的基本原理是原语放置在堆栈上,而不是堆上,因此不受垃圾回收的影响。

【问题讨论】:

    标签: java performance bigdecimal


    【解决方案1】:

    现在的 JVM 在处理短期对象的创建和销毁方面已经相当不错了,所以这已经不是以前的担心了。

    我建议建立一个你想做的模型,然后测量它。这将比您可能得到的任何“理论”答案更有价值:-)

    看看您的特定问题域,我过去使用过的类似系统在您想要使用 BigDecimal 的数据中使用双精度时工作得非常好,可能值得重新审视您在该领域的想法。粗略看一下 BigDecimal 会发现它有 5 或 6 个字段,并且单个 double 的额外内存消耗可能超过您拥有的任何功能优势。

    【讨论】:

    • 其中一个字段是BigInteger(而BigInteger 的字段之一是int[])(Sun 实现)。
    • 好点。我还注意到那里有一个字符串,但我知道它只在 toString() 调用期间填充
    • 我很难相信基于双倍数量和价格的交易系统可能会运行得很好,更不用说很好了。正确性几乎不是人们应该重新检查的“功能优势”。
    • +1 表示“构建和测量”。写得太多了,好像一般趋势适用于每种情况。
    • 好的cmets。双打给你大约 50 位的精度(大约 17 位小数)。如果您需要更多,大整数可能比自己构建更好。
    【解决方案2】:

    BigDecimal 的性能确实比longdouble 甚至Long 低很多。这是否会对您的应用程序性能产生重大影响取决于您的应用程序。

    我建议找到应用程序中最慢的部分,并对其进行比较测试。它仍然足够快吗?如果没有,您可能想要编写一个包含单个long 的小型不可变类,可能会检查溢出。

    【讨论】:

      【解决方案3】:

      如果您正在开发一个低延迟交易程序,并且您真的想在延迟方面竞争,那么BigDecimal 不适合您,就这么简单那样。在微秒很重要的地方,对象创建和任何十进制数学都太昂贵了。

      我认为对于几乎其他所有人来说,使用BigDecimal 是不费吹灰之力的,因为它对应用程序性能几乎没有可见影响。

      在做出交易决策的延迟关键系统中,任何不可预测的垃圾收集暂停是完全不可能的,因此虽然当前的垃圾收集算法在正常使用中非常出色,但它们是当 5 毫秒的延迟可能会花费您很多钱时,不一定合适。我希望大型系统是以非常非 OOP 的风格编写的,除了一些内部字符串(用于代码等)之外,几乎没有使用任何对象。

      您当然需要使用 double(甚至是 float)并获得准确性,否则使用 long 并以美分、十分之一美分或聪(无论最小的记账单位是什么)衡量所有金额。

      【讨论】:

      • 如果 BidD 不适合我,那是什么?我不使用双精度数(因为它给浮点数带来了很多新问题 - 我使用的数字自然是小数)。
      • +1 表示关于性能竞争的关键点。就像关于老虎和跑鞋的笑话一样,绝对数字很少重要,比重要的要好/差。
      • @valery_la99 - 我已添加到我的答案中
      • 请参阅github.com/subes/invesdwin-util#decimal 了解直接使用 Double 的替代方法,方法是使用围绕它的流畅 API,因为它是为财务策略回测而设计的,速度非常快。
      【解决方案4】:

      我不确定您的要求是什么,但通常在进行财务计算时,无法承受浮点类型造成的准确性损失。在处理金钱时,通常准确性和适当的舍入比效率更重要。
      如果您不必处理百分比并且所有金额都是整数,则可以使用整数类型(int、long 甚至 BigInteger),其中一个表示您的货币单位的 0.01。
      即使您认为使用 double 类型可以承受准确度,也可能值得先尝试使用 BigDecimal 并检查它是否真的会减慢您的速度。

      【讨论】:

        【解决方案5】:

        最大的问题是:您真的需要任意精度的十进制计算吗?如果计算只是为了分析数据并据此做出决策,那么最低有效位之间的舍入和二进制表示伪影可能与您无关;继续使用double(并分析numerical stability的算法)。

        如果您实际上是在进行数字必须相加且精度绝对重要的交易,那么double 不是一个选择。也许您可以将应用程序的这两个部分分开,并仅在事务部分使用BigDecimal

        如果这是不可能的,那么你就很不走运了。你需要一个BCD 数学库,我认为Java 没有。您可以尝试自己编写,但工作量很大,而且结果可能仍然没有竞争力。

        【讨论】:

          【解决方案6】:

          我在一个对应用程序进行性能评估和优化的团队工作,最近有一个应用程序正在使用 Java Big Decimal。在内存利用率方面观察到了显着的性能问题。后来我们改用 Newton Raphson,这使我们能够保持计算的准确性,并在大小数方面表现出明显更好的性能。

          补充一下.. 当我们使用双打时,我们看到预期的准确性大幅下降

          【讨论】:

            【解决方案7】:

            为什么不使用带有隐含小数位数的 long 呢?例如,假设您隐含了 8 个小数位,那么 0.01 就是 1000000。

            【讨论】:

              猜你喜欢
              • 2019-06-19
              • 1970-01-01
              • 2022-08-04
              • 1970-01-01
              • 1970-01-01
              • 2012-10-09
              • 2011-06-27
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多