Модуль Cache Julia для быстрого запуска и использования в Python

У меня есть модуль Julia, с которым мне нужно взаимодействовать с моей кодовой базой python. Для этого я использую pyjulia так.

import julia

j = julia.Julia()
j.include('./simulation/n-dof/dynamics.jl')
j.using("Dynamics")
print(j.sim([1,2,3],[1,2,3]))

Однако это замедляет все, поскольку Julia необходимо скомпилировать модуль, который я использую.

Модуль использует функцию экспорта 1 и внутренне использует ForwardDiff для некоторых вычислений. Он вычисляет производные от динамической системы. Модуль, скорее всего, не изменится в обозримом будущем. Я читал о __precompile()__ и PackageCompiler.jl но я не совсем понимаю внутреннюю работу и как ее использовать.

Таким образом, есть способ либо кэшировать модуль в изображении системы Julia (из чего я понимаю, почему чистый запуск Julia выполняется быстро)? Или лучше скомпилировать его в двоичный файл, а потом как-то назвать его через python? Мне нужно передать аргументы экспортируемой функции.

Пример модуля динамики, который я использую для тестирования:

module Dynamics
    function sim(a,b)
        return 1
    end

    export sim

end

Ответ 1

Это сложный вопрос. Я дам самый простой подход. Я предполагаю, что вы используете Julia 0.7 (он должен быть выпущен очень скоро):

A. создать пакет в Джулии; переключитесь на диспетчер пакетов в Julia REPL и в сессии менеджера Pkg (вы переключитесь на него с помощью ]) write: generate Ex1 (Ex1 будет нашим пакетом)

B. у вас будет создан скелет пакета; добавьте любые зависимости, которые вам нужны. Я принимаю ваш простой пример. Затем файл Ex1.jl в каталоге src должен быть изменен на:

__precompile__()
module Ex1
export sim
sim(a,b) = 1
precompile(sim, (Int, Int))
end

C. ключевая строка precompile(sim, (Int, Int)) поскольку вы принудительно прекомпиляции функции sim - вам нужно указать типы аргументов, для которых вы хотите, чтобы функция была предварительно скомпилирована

D. измените каталог Julia в каталог пакета Ex1 и activate. запись activate. в режиме менеджера Pkg для активации пакета

E. пока все еще в режиме менеджера Pkg записывают precompile; это вызовет предварительную компиляцию вашего модуля. Вы можете проверить DEPOT_PATH[1] в compiled/v0.7/ подкаталоге, который был создан в каталоге Ex1 и содержит файл ji с предварительно скомпилированным содержимым вашего пакета

Как проверить, действительно ли пакет предварительно скомпилирован? Выйдите из Julia и введите его снова в каталог пакета Ex1 (чтобы иметь чистый REPL). Теперь пиши:

A. activate. в режиме менеджера Pkg (чтобы Ex1)

B. Вернитесь в нормальный режим Джулии и выполните следующее:

julia> using Ex1

julia> @time sim(1,1)
  0.000003 seconds (5 allocations: 208 bytes)
1

julia> @time sim(1,1)
  0.000003 seconds (4 allocations: 160 bytes)
1

julia> @time sim(1.0,1.0)
  0.000182 seconds (394 allocations: 26.641 KiB)
1

julia> @time sim(1.0,1.0)
  0.000002 seconds (4 allocations: 160 bytes)
1

Вы можете видеть, что sim(1,1) не скомпилирован, поскольку мы предварительно скомпилировали sim для (Int,Int) аргументов, но sim(1.0,1.0) пришлось скомпилировать, поскольку мы не прекомпилировали sim для (Float64,Float64).

Вкратце: главное, чтобы понять, что вы прекомпилируете не функцию, а конкретный метод этой функции. Вам придется предварительно скомпилировать все методы, которые вы использовали бы таким образом. Все остальное в приведенном выше объяснении - это технические шаги, чтобы Джулия сделала предварительную компиляцию.

Дополнительные вопросы, которые следует учитывать:

  • вы можете построить пакет в системный образ, это сложно; здесь у вас есть инструкции: https://docs.julialang.org/en/latest/devdocs/sysimg/; Вы также можете проверить PackageCompiler.jl, о котором вы упомянули, чтобы помочь вам в этом процессе; можно ожидать, что статическая прекомпиляция станет намного лучше в будущем;
  • для того, чтобы ваш пакет был предварительно скомпилирован, все зависимости должны быть предварительно скомпилированы.

Я надеюсь, что это работает для вас.