Подтвердить что ты не робот

Реальный мир Clojure советы по настройке производительности?

Я вижу некоторые серьезные замедления в "некоторых" частях приложения Clojure. У кого-нибудь есть какие-либо реальные подсказки о том, как они настроили настройку производительности в приложении Clojure?

4b9b3361

Ответ 1

Мои личные советы:

  • Сначала проверьте свой алгоритм - вы несете стоимость O (n ^ 2), когда это действительно должно быть O (n.log n)? Если вы выбрали плохой алгоритм, остальная настройка - пустая трата времени.
    • Имейте в виду общие "gotchas", такие как O (n) стоимость прохождения списка/последовательности.
    • Воспользуйтесь преимуществами функций Clojure, таких как стоимость O (1) копирования большой постоянной структуры данных или стоимости O (log32 n) для доступа к карте/множеству/вектору.
  • Выберите из Clojure основных конструкций мудро:
    • атом отлично работает, когда вам нужны некоторые изменяемые данные, например. обновление некоторых данных в цикле
    • Если вы собираетесь последовательно перемещать некоторые данные, используйте список, а не вектор или карту, так как это позволит избежать создания временных объектов при прохождении последовательности.
    • При необходимости используйте deftype/defrecord/defprotocol. Они в значительной степени оптимизированы и, в частности, должны быть предпочтительными для детерструкции/мультиметодов начиная с Clojure 1.2 и далее.
  • Воспользуйтесь возможностями Clojure concurrency:
    • pmap и будущее - это относительно простые способы использования нескольких ядер при одновременном выполнении нескольких независимых вычислений.
    • Помните, что из-за Clojure неизменяемых устойчивых структур данных создание и работа с несколькими копиями данных очень недорогая. Вам также не нужно беспокоиться о блокировке при съемке снимков.....
  • Если вы взаимодействуете с Java-кодом, используйте "(set! * warn-on-reflection * true)" и устранить все предупреждения отражения. Отражение - одна из самых дорогих операций, и будет действительно замедлять ваше приложение, если оно будет сделано повторно.
  • Если вам по-прежнему нужна большая производительность, укажите наиболее важные для производительности компоненты вашего кода (например, 5% строк, в которых приложение тратит 90% + процессорного времени), подробно проанализируйте этот раздел и разумно примените следующие правила:
    • Избегайте лень. Лень - отличная функция, но с некоторыми дополнительными накладными расходами. Имейте в виду, что многие из Clojure общих функций последовательности/списка являются ленивыми (например, для, map, partition). loop/recur, dotimes и уменьшить ваши не ленивые друзья.
    • Используйте примитивные подсказки и непроверенную арифметику, чтобы сделать арифметический/числовой код быстрее. Примитивы намного быстрее, чем Clojure арифметика BigInteger по умолчанию.
    • Сократить выделение памяти - старайтесь избегать создания слишком большого количества ненужных промежуточных данных (векторов, списков, карт, не примитивных чисел и т.д.). Все распределения налагают небольшое количество дополнительных накладных расходов, а также приводят к большему количеству дополнительных пауз GC с течением времени (это может вызвать большую озабоченность, если вы пишете игровое/мягкое приложение в реальном времени.)
    • (Ab) использует массивы Java - не очень идиоматично в Clojure, но aget/aset/areduce и друзья очень быстрые (они извлекают выгоду из множества оптимизаций JVM!!). (Ab) используют примитивные массивы для дополнительных бонусных очков.
    • Использовать макросы - генерировать безошибочный, но быстрый код во время компиляции, где это возможно.

Выполнение всего вышеописанного должно получить довольно хорошую производительность из Clojure кода - с тщательной настройкой, я обычно был достаточно близок к чистой производительности Java, что довольно впечатляет для динамического языка!

Ответ 2

Вы можете использовать JVisualVM для профилирования кода Clojure (см. JVisualVM и Clojure для примера). Это должно по крайней мере указывать на правильное направление медленного кода.