使用BigDecimal会如何影响应用程序的性能?

15

我希望在一款每秒处理数千个订单和执行报告的低延迟交易应用程序中,使用BigDecimal来表示价格和金额等任意精度数字。

我不会对它们进行太多的数学运算,所以问题不在于BigDecimal本身的性能,而在于大量的BigDecimal对象如何影响应用程序的性能。

我的担忧是,大量短暂存在的BigDecimal对象会给GC带来压力,并导致CMS收集器中更长的Stop-The-World暂停时间——这绝对是我想避免的。

请确认我的顾虑并建议使用BigD以外的替代方案。如果您认为我的顾虑是错误的,请解释一下原因。

更新:

感谢所有回答者。我现在相信使用BigDecimal会影响我的应用程序的延迟(尽管我仍然计划对其进行测量)。

目前我们决定坚持“非常非OOP”的解决方案(但没有精度损失)——使用两个int,一个用于尾数,另一个用于指数。之所以采用这种方法,是因为基本类型被放置在栈上,而不是堆上,因此不受垃圾回收的影响。

7个回答

15
如果您正在开发一个低延迟的交易程序,并且真正想在延迟方面竞争,那么 BigDecimal 对您来说并不适用,这就是简单如此。在微秒级别的应用中,对象创建和任何十进制数学计算都太昂贵了。
我认为对于几乎所有其他人来说,使用 BigDecimal 是一项毫无疑问的选择,因为它对应用程序性能影响很小。
在具有延迟关键系统做出交易决策时,任何不可预测的垃圾收集暂停都是绝对不能容忍的,因此尽管当前的垃圾收集算法在正常情况下非常棒,但在延迟可能会让您损失大量金钱的情况下,它们并不一定适用。我预计大型系统采用非面向对象的编程风格,除了一些内部字符串(用于代码等)之外,很少或根本不使用对象。
您肯定需要使用 double(甚至是 float)并承受精度损失,或者使用 long 并以分、十分之一分或 satoshis(最小的记账单位)来衡量所有金额。

如果BidD不适合我,那么什么适合我呢?我不想使用double类型(因为它会带来一系列浮点数问题——而我操作的数字通常是小数)。 - vtrubnikov
2
+1 是关于在性能上竞争的关键点。就像有关老虎和跑鞋的笑话一样,绝对数字很少起到重要作用,好于/劣于才是最重要的。 - soru
@valery_la99 - 我已经更新了我的回答。 - oxbow_lakes
请参考 https://github.com/subes/invesdwin-util#decimal,使用围绕它的流畅API直接处理Double的替代方案,该API专为金融策略回测而设计,速度非常快。 - subes

8

现在的JVM在处理短暂对象的创建和销毁方面已经相当出色了,所以这不再是过去那样令人担忧的问题。

我建议您先建立一个所需操作的模型并进行测试。这比您可能得到的任何“理论”答案都要有价值 :-)

针对您特定的问题领域,我曾经处理过的类似系统使用double来代替您想要使用BigDecimal的数据,并且重新审视这个领域的思考方式可能是值得的。简单地查看BigDecimal,发现它有5或6个字段,而超过单个double的额外内存消耗可能会抵消您所拥有的任何功能性好处。


其中一个字段是 BigInteger(而 BigInteger 的一个字段是 int[])(Sun 实现)。 - Tom Hawtin - tackline
1
好观点。我也注意到其中有一个String,但我理解那只是在调用toString()时填充的。 - Brian Agnew
2
我觉得很难相信,一个基于双倍数的交易系统能够正常工作,更别说运作良好了。正确性根本不是应该重新评估的“功能收益”。 - Michael Borgwardt
2
+1 为“构建与衡量”。很多时候,人们会将一般趋势适用于所有情况,这种写法太过极端。 - CPerkins
1
良好的注释。双精度浮点数可以提供大约50位的精度(约17位小数)。如果你需要更多精度,比起自己构建一个变量,大整数可能更合适。 - Mike Dunlavey
显示剩余2条评论

5
BigDecimal 的性能比起 longdouble 或者是 Long 都要慢很多。但这是否会对你的应用程序的性能造成重大影响,还取决于你的应用程序。

我建议找出你的应用程序中最慢的部分,并对其进行比较测试。它是否仍然足够快?如果不是,你可能需要编写一个小的不可变类,其中包含一个单独的 long,并可能检查溢出情况。


4
重要的问题是:你是否真正需要任意精度的十进制计算?如果计算仅用于分析数据并基于此做出决策,则四舍五入和二进制表示中最不重要的位数可能与您无关;只需使用double(并分析您的算法以获得数值稳定性)。

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

如果这不可能,那么你就非常倒霉了。您需要一个BCD数学库,而我认为Java没有这样的库。您可以尝试编写自己的库,但这将是很多工作,并且结果可能仍然无法竞争。


2
为什么不使用带有隐含小数位数的long整型?例如,假设您有8个隐含的小数位数,则0.01将变为1000000。

1

我在一个团队工作,负责对应用程序进行性能评估和优化。我们最近遇到了一个使用 Java Big Decimal 的应用程序,发现存在内存利用方面的显著性能问题。后来我们转而使用牛顿-拉弗森算法,在保持计算精度的同时,大幅提升了性能表现,相比之下要好得多。

另外补充一点,在使用 double 类型时,如预期所料,我们发现精度严重下降。


1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接