Как использование BigDecimal повлияет на производительность приложения?
Я хочу использовать BigDecimal для представления чисел произвольной точности, таких как цены и суммы в торговом приложении с низкой задержкой, с тысячами заказов и отчетов об исполнении в секунду.
Я не буду делать много математических операций над ними, поэтому речь идет не о производительности BigDecimal как таковой, а о том, как большие объемы объектов BigDecimal будут влиять на производительность приложения.
Моя забота заключается в том, что огромное количество недолговечных объектов BigDecimal будет создавать нагрузку на GC и привести к большим остановкам Stop-The-World в сборщике CMS - и это определенно то, чего я бы хотел избежать.
Не могли бы вы подтвердить мои проблемы и предложить альтернативы использованию BigD? Кроме того, если вы считаете, что мои проблемы ошибочны, пожалуйста, объясните, почему.
Обновление
Спасибо всем, кто ответил. Теперь я убежден, что использование BigDecimal приведет к задержке моего приложения (хотя я все еще планирую его измерить).
В настоящее время мы решили придерживаться "очень не-ООП" (но без достижения точности) - используйте два int
s, один для мантиссы и другой для показателя. Обоснование этого заключается в том, что примитивы помещаются в стек, а не в кучу, и, следовательно, не подлежат сборке мусора.
Ответы
Ответ 1
Если вы разрабатываете торговую программу с низкой задержкой и вы действительно хотите конкурировать в латентных условиях, то BigDecimal
не для вас, это так просто. Где микросекунды имеют значение, создание объекта и любая десятичная математика слишком дороги.
Я бы сказал, что для почти всех остальных использование BigDecimal
не требует больших усилий, поскольку оно мало влияет на производительность приложения.
В критически важных системах, принимающих решения о покупке, любые непредсказуемые паузы в сборке мусора полностью исключают вопрос, так что существующие сборники мусора являются фантастическими при нормальном использовании, они не обязательно подходят, когда задержка 5 миллисекунд могут стоить вам много денег. Я ожидал бы, что большие системы были написаны в стиле, отличном от ООП, с небольшими или вообще отсутствующими объектами, кроме некоторых интернированных строк (для кодов и т.п.).
Вам обязательно нужно будет использовать double
(или даже float
) и получить точность.
Ответ 2
JVM довольно хороши в настоящее время с точки зрения обработки создания и уничтожения короткоживущих объектов, так что не беспокоиться об этом некогда.
Я бы рекомендовал создать макет того, что вы хотите сделать, и измерить его. Это будет стоить намного больше, чем любые "теоретические" ответы, которые вы можете получить: -)
Глядя на ваш конкретный проблемный домен, аналогичные системы, над которыми я работал в прошлом, очень хорошо работают с использованием удвоений для данных, которые вы хотите использовать BigDecimal, и, возможно, стоит пересмотреть свое мышление в этой области. Беглый взгляд на BigDecimal показывает, что он имеет 5 или 6 полей, а дополнительное потребление памяти в течение одного двойника может перевесить любые преимущества функциональности, которые у вас есть.
Ответ 3
BigDecimal
имеет производительность намного ниже, чем, скажем, long
, double
или даже long
. Будет ли это иметь существенное значение для производительности вашего приложения, зависит от вашего приложения.
Я предлагаю найти самую медленную часть вашего приложения и выполнить сравнительный тест. Это все еще достаточно быстро? Если нет, вы можете написать небольшой неизменяемый класс, содержащий один long
, возможно, проверяющий переполнение.
Ответ 4
Большой вопрос: действительно ли вам нужны точные десятичные вычисления точности? Если вычисления выполняются только для анализа данных и принятия решений на основе этого, то артефакты округления и двоичного представления среди наименее значимых битов, вероятно, не имеют к вам отношения; просто используйте double
(и проанализируйте свои алгоритмы для численная стабильность).
Если вы на самом деле делаете транзакции, в которых номера должны складываться, а точность имеет значение абсолютно, то double
не является опцией. Возможно, вы можете разделить эти две части вашего приложения и использовать BigDecimal
только в транзакции.
Если это невозможно, то вам не повезло. Вам понадобится математическая библиотека BCD, и я не думаю, что у нее есть Java. Вы можете попробовать написать свой собственный, но это будет много работы, и результат может быть еще неконкурентоспособным.
Ответ 5
почему вы не используете длинный номер с подразумеваемым числом десятичных знаков? Например, предположим, что у вас есть 8 знаков после запятой, тогда 0.01 будет 1000000.
Ответ 6
Я не уверен, каковы ваши требования, но, как правило, при составлении финансовых расчетов нельзя получить точность, вызванную типами с плавающей запятой. Обычно точность и правильное округление важнее эффективности при работе с деньгами.
Если вам не нужно иметь дело с процентами, и все суммы целые, вы можете использовать целые типы (int, long или даже BigInteger) с одним значением 0.01 вашей валютной единицы.
И даже если вы считаете, что можете получить точность с типом double
, возможно, стоит попробовать сначала с BigDecimal и проверить, действительно ли это замедляется для вас.
Ответ 7
Я работаю в команде, которая проводит оценки производительности и оптимизации приложений, недавно было одно приложение, использующее Java Big Decimal. Значительные проблемы с производительностью наблюдались при использовании памяти. Позднее мы переключились на Newton Raphson, который позволил нам поддерживать точность расчетов и показал значительно лучшую производительность до большого десятичного знака.
Просто добавлю.. когда мы использовали двойники, мы увидели огромную потерю точности, как ожидалось