Performance
Стоит понимать, что оптимизирующий компилятор OCaml'а хоть и имеет под собой достаточно теории, но всё равно не сравниться с LLVM или GCC.
Документация
Важно
Наблюдения описываются применительно к ванильному компилятору версии 5.2
. Для изучения результата компиляции использовался сервис godbolt.
Сборка с оптимизациями
Смотрите Release-сборка проекта и flambda.
Склейка строк
Если вам требуется склеить больше двух строк — не используйте оператор Stdlib.(^)
. Заместо него используйте модули Format
, Printf
или подобное.
Пример
(* Плохо! *)
let greet name =
(* Почему: две аллокации (по одной на каждую склейку) *)
print_endline @@ "Привет, " ^ name ^ "!"
(* Хорошо *)
let greet name =
(* Почему: примерно одна аллокация *)
Printf.printf "Привет, %s!\n" name
Компилятор никак не сворачивает строковые константы, то есть склейка констант производится в рантайме! Будьте осторожны.
Микрооптимизации
Использование буфера дает явный контроль над выделением памяти.
let greet name =
let buf = Buffer.create (16 + String.length name) in
Buffer.add_string buf "Привет, ";
Buffer.add_string buf name;
Buffer.add_string buf "!\n";
Buffer.output_buffer stdout buf
Частичное применение
Старайтесь не определять ваши функции через частичное применение. Функция это сложный объект, проще вернуть любое другое значение.
Пример
(* Генерирует больше кода! *)
let factorial =
let rec aux acc n = (* ... *)
in aux 1
(* Эффективно *)
let factorial n =
let rec aux acc n = (* ... *)
in aux 1 n
Memory management
Ахтунг
Эта секция требует больше подробностей и большей квалификации в устройстве рантайма.
Материалы
Наблюдение потребления памяти для OCaml 5
Складывается ощущение, что сборщик мусора очень не охотно собирает мусор, так как при растущих на грузках программу, её потребление памяти начинаются неограниченно увеличиваться, а когда нагрузки нет, то она оставляет при себе весь объём памяти.
Inlining
Компилятор умеет понимать, когда стоит заинлайнить ту или иную функцию, но если вы хотите явно потребовать этого, то для этого используйте аттрибут.
Аттрибут inline
при определении функции, говорящая, что эта функция должна быть заинлайнена, но для этого не должна быть частично применённой.
let[@inline] add x y = x + y
Аттрибут inlined
может использоваться при применение функции, что бы заинлайнить конкретную функцию, но для этого она не должна быть частично применённой.
let _ = (add[@inlined]) 10 0