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