Замена горячего кода в erlang - программирование

Замена горячего кода в erlang

Я работаю над своим первым настоящим проектом в erlang, однако этот код упрощен для краткости. Я хочу иметь возможность загружать более новую версию файла в мой проект удаленно, пока он работает. Я читал об использовании такого поведения, как gen_server или gen_fsm, у которого это бесплатно. Хотя это может привести к результату, я хочу использовать это, чтобы узнать, как это сделать, а не просто сделать это. Я прочитал документы о замена кода, а бит LYSE о Hot Code Любить, между прочим, но я не смог найти ничего, что работает на то, что я делаю, поэтому вот основная идея.

-module(reloading).

-export([loop/0]).

loop() ->
    receive
        upgrade ->
            ?MODULE:loop();
        hello ->
            io:format("This is a test~n"),
            loop();
        _ ->
            loop()
    end.

Я просто зацикливаюсь на том, что могу отправить сообщение upgrade, и он загрузит более новую версию кода.

$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.1  (abort with ^G)
1> c(reloading).
{ok,reloading}
2> Loop = spawn(reloading, loop, []).
<0.39.0>
3> Loop ! hello.
This is a test
hello

В этот момент я меняю 10 строк на io:format("I have changed this!~n"),

4> Loop ! upgrade.
upgrade
5> Loop ! hello.  
This is a test
hello

Я ожидаю, что этот вызов hello напечатать I have changed this! not This is a test. Я знаю, что могу просто позвонить c(reloading). и выполнить эту работу так, как ожидалось, но я хочу отправить фактическое сообщение о проекте, а не вручную обновлять код. Итак, где мой разрыв? Что я делаю неправильно, что я должен делать, чтобы нагрузить этот код? Как упоминалось ранее, я ищу решение без OTP для образования.

4b9b3361

Ответ 1

Чтобы получить явный ответ, я публикую это.

Используя @rvirding предложение об использовании модуля code, я изменил его так:

-module(reloading).

-export([loop/0]).

loop() ->
    receive
        upgrade ->
            code:purge(?MODULE),
            compile:file(?MODULE),
            code:load_file(?MODULE),
            ?MODULE:loop();
        hello ->
            io:format("This is a test~n"),
            loop();
        _ ->
            loop()
    end.

Первый код: очистить старый ?MODULE, затем скомпилировать: файл новый файл и наконец, code: load_file новый ?MODULE. Это работает, как я и предполагал.

$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.1  (abort with ^G)
1> Loop = spawn(reloading, loop, []).
<0.34.0>
2> Loop ! hello.
This is a test
hello

Измените строку на io:format("I have changed this!~n"),

3> Loop ! upgrade.                   
upgrade
4> Loop ! hello.  
I have changed this!
hello

Ответ 2

В то время как erlang может обрабатывать две версии модуля, а вызов функции с помощью mod:func(...) будет всегда вызывать последнюю версию модуля (если функция экспортируется), вам все равно придется загружать новую версию модуля в систему Erlang, Вы не можете ожидать, что он автоматически обнаружит, что у вас где-то есть новая версия модуля, найдите его, скомпилируйте и загрузите.

N.B. компиляция и загрузка - это две разные вещи. Таким образом, c(mod). компилирует и модуль, а l(mod). просто загружает объектный код (.beam файл) уже скомпилированного модуля. Компилятор Erlang вызывается из модуля compile, и он просто компилирует и генерирует файл .beam, а загрузка кода обрабатывается модулем code.

Ответ 3

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

Вы должны взглянуть на sync или active.