Если скрипт Julia запускается из командной строки, нужно ли его каждый раз перекомпилировать? - PullRequest
0 голосов
/ 30 мая 2018

Я прочитал довольно много документации и вопросов, но я все еще не уверен в этом.

В разделе документации Профилирование предлагается сначала запустить целевую функцию вREPL один раз, так что он уже скомпилирован перед профилированием.Однако что, если скрипт довольно сложный и предназначен для запуска в командной строке, принимая аргументы?Когда процесс julia завершается, и я запускаю сценарий во второй раз, выполняется ли компиляция снова?Сообщения типа https://stackoverflow.com/a/42040763/1460448, Джулия каждый раз компилирует скрипт? дает противоречивые ответы.Они также кажутся старыми, в то время как Джулия постоянно развивается.

Мне кажется, что вторая пробежка занимает ровно столько же времени, сколько и первая пробежка в моем опыте.Время запуска довольно долго.Как мне оптимизировать такую ​​программу?Добавление __precompile__(), похоже, совсем не изменило время выполнения.

Кроме того, что мне делать, если я хочу профилировать такую ​​программу?Все ресурсы по профилированию рассказывают об этом в REPL.

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Я немного не согласен с моими коллегами.Существуют абсолютно допустимые сценарии, в которых можно было бы использовать сценарии julia.Например, когда у вас есть конвейер скриптов (например, matlab, python и т. Д.), И вам нужно подключить скрипт julia где-то посередине всего этого, и управлять всем конвейером из скрипта оболочки.Но, независимо от варианта использования, высказывание «просто используйте REPL» не является правильным ответом на этот вопрос, и даже если один не может придумать «действительные» сценарии, это все еще вопросСтоит ответить прямо, а не обходным путем.

Я согласен с тем, что решение, имеющее соответствующий код, состоит в том, чтобы обернуть все критически важные элементы, которые необходимо предварительно скомпилировать, в модули и оставить только все, кроме самых внешних команд.на верхнем уровне сценария.В любом случае это не слишком отличается от мира Matlab или C ++, где вы должны писать основательные функции и рассматривать вашу функцию script / main только как своего рода очень короткую точку входа верхнего уровня, задача которой - просто подготовитьначальную среду, а затем запустите эти более специализированные функции соответственно.

Вот пример того, что я имею в виду:

# in file 'myscript.jl'
push!( LOAD_PATH, "./" )
import MyPrecompiledModule
println( "Hello from the script. The arguments passed into it were $ARGS" )
MyPrecompiledModule.exportedfun()

# in file 'MyPrecompiledModule.jl' (e.g. in the same directory as myscript.jl)
__precompile__()
module MyPrecompiledModule
  export exportedfun;
  function innerfun()
    println("Hello from MyPrecompiledModule.innerfun");
  end

  function exportedfun()
    innerfun()
    print("Hello from MyPrecompiledModule.exportedfun");
  end
end

В приведенном выше сценарии скомпилированная версияMyPrecompiledModule будет использоваться в скрипте (и если он не существует, он будет скомпилирован при первом запуске скрипта), поэтому любые оптимизации от компиляции не будут потеряны в конце скрипта, но вы все равнов конечном итоге получим автономный скрипт julia, который вы можете использовать как часть процесса конвейерного скрипта оболочки bash, которому вы также можете передавать аргументы.Затем сценарий myscript.jl должен только передать их импортированным функциям модуля, если необходимо, и выполнить любые другие команды, которые вас не особо волнуют, когда они компилируются / оптимизируются или нет, например, выполнять тесты, предоставлять инструкции по использованию сценария.и т. д.

0 голосов
/ 31 мая 2018

Пожалуйста, исправьте меня, если я ошибаюсь, но звучит так, будто вы написали какой-то длинный скрипт, скажем, myfile.jl, а затем из командной строки вашей ОС вы вызываете julia myfile.jl args....Это правильно?Кроме того, похоже, что myfile.jl не определяет многое в смысле функций, а представляет собой просто последовательность команд.Это правильно?Если так, то, как было предложено в комментариях к вопросу, это не типичный рабочий процесс для Юлии по двум причинам:

1) Вызов Джулии из командной строки, т. Е. julia myfile.jl args...эквивалентно открытию REPL, выполнению команды include на myfile.jl и последующему закрытию REPL.Первоначальный вызов include скомпилирует все методы, которые необходимы для операций в myfile.jl, что требует времени.Но поскольку вы работаете из командной строки, после завершения include REPL автоматически закрывается, и весь этот скомпилированный код выбрасывается.Это то, что имеет в виду DNF, когда он говорит, что рекомендуемый рабочий процесс должен работать в одном сеансе REPL, и не закрывайте его до тех пор, пока вы не закончите в течение дня или если вы намеренно не захотите перекомпилировать все используемые вами методы.

2) Даже если вы работаете в одном сеансе REPL, крайне важно обернуть практически все, что вы делаете в функциях (это совсем другой рабочий процесс по сравнению с такими языками, как Matlab).Если вы сделаете это, Джулия скомпилирует методы для каждой функции, которые специализируются на типах входных аргументов, которые вы используете.По сути, поэтому Юлия так быстро.После того, как метод скомпилирован один раз, он остается доступным для всего сеанса REPL, но удаляется при закрытии REPL.Крайне важно, что если вы не заключаете свои операции в функции, то эта специализированная компиляция не происходит, и поэтому вы можете ожидать очень медленный код.В юлии мы называем это «работой в глобальном масштабе».Обратите внимание, что эта особенность Джулии поддерживает стиль кодирования, состоящий из разбивки ваших задач на множество небольших специализированных функций, а не одного бегемота, состоящего из 1000 строк кода.Это хорошая идея по многим причинам.(в моей собственной кодовой базе многие функции являются однострочными, большинство - 5 или менее строк)

Два вышеприведенных пункта абсолютно необходимо понять, если вы работаете в Julia.Однако, как только вы освоитесь с ними, я бы порекомендовал вам фактически поместить все свои функции в modules , а затем вызывать ваши модули из активного сеанса REPL всякий раз, когда вам это нужно.Это дает дополнительное преимущество, заключающееся в том, что вы можете просто добавить оператор __precompile__() в верхней части вашего модуля, а затем julia прекомпилирует часть (но не обязательно весь) кода в этом модуле.Как только вы это сделаете, предварительно скомпилированный код в вашем модуле не исчезнет, ​​когда вы закроете REPL, так как он хранится на жестком диске в файле .ji.Таким образом, вы можете начать новый сеанс REPL, набрав using MyModule, и ваш предварительно скомпилированный код будет немедленно доступен.Его нужно будет перекомпилировать, только если вы измените содержимое модуля (и все это происходит автоматически).

...