Не могу ничего отправить в порожденный процесс Erlang

У меня есть следующий код Erlang:

#!/usr/bin/env escript
%%! -pz ../deps/amqp_client ../deps/rabbit_common ../deps/amqp_client/ebin ../deps/rabbit_common/ebin

% RMQ module
-module(rmq).
-export([main/1, send/1, validate/0, test/0]).
-include_lib("../deps/amqp_client/include/amqp_client.hrl").

main(_) ->
    %send(<<"test_esio">>),
    %validate(),
    Pid = spawn(rmq, test, []),
    % Pid = spawn(fun() -> test() end), <= I've tried this way too
    Pid ! s.

test() ->
    receive
        s ->
            io:format("BAR ~n"),
            send(<<"esio">>),
            test();
        get ->
            validate(),
            test();
        _ ->
            io:format("FOO"),
            test()
    end.

Я запускаю это с: excript rmq.erl

Этот код не работает. Похоже, нерест не работает.

Остальная часть моего кода работает, функция отправки и проверки корректно работает, если я запускаю его из main (я прокомментировал его). Что я делаю не так?

Извините, может быть, это глупый вопрос, но я новичок в Erlang. Я попытался найти ответ в Интернете и книгах, и мне не удалось...

1 ответ

Решение

Проблема на самом деле не в spawn, а в путанице в модуле /escript.

В двух словах, escript-файл на самом деле не является модулями, не с точки зрения Erlang VM, даже если вы используете -module() директивы. Они интерпретируются, и не компилируются вообще, и определенно их нельзя вызвать с помощью модуля, такого как "rmq:test()", или в вашем случае через динамический вызов модуля с помощью spawn,

Самое простое решение - это отдельный скрипт от реальных модулей. В вашем rmq.es Вы бы просто запустили какой-то правильный модуль:

#!/usr/bin/env escript
%%! -pz ../deps/amqp_client ../deps/rabbit_common ../deps/amqp_client/ebin ../deps/rabbit_common/ebin

main(_) ->
  rmq:start().

А там в модуле rmq.erl:

-module(rmq).
-export([start/0, send/1, validate/0, test/0]).
-include_lib("../deps/amqp_client/include/amqp_client.hrl").

start() ->
    Pid = spawn(rmq, test, []),

    %% Pid = spawn(?MODULE, test, []),  %% works with macro too

    %% Pid = spawn(fun() -> test() end), <= I've tried this way too
    Pid ! s.

test() ->
    receive
        s ->
            io:format("BAR ~n"),
            send(<<"esio">>),
            test();
        get ->
            validate(),
            test();
        _ ->
            io:format("FOO"),
            test()
    end.

Или вы можете просто запустить этот модуль без сценария, с -run флаг как это

erl -pz deps/*/ebin -run rmq start 

РЕДАКТИРОВАТЬ относительно проблем компиляции

Вы компилируете свои модули с erlc командование Чтобы просто скомпилировать использование erlc rmq.erl, который будет производить rmq.beam файл в текущем каталоге. Но соглашение состоит в том, чтобы сохранить все ваши исходные файлы в src каталог, все скомпилированные файлы в ebin direcory, и такие вещи, как run-scripts могут быть размещены в верхнем каталоге. Что-то вроде того:

project
|-- ebin
|   |-- rmq.beam
|
|-- src
|   |-- rmq.erl
|
|-- rmq.es

Предполагая, что вы запускаете все свои команды оболочки формы project каталог, чтобы скомпилировать весь файл из src и место .beam двоичные файлы в ebin использование erlc src/rmq.erl -o ebin, или же erlc src/* -o ebin В документации вы можете найти объяснение -o флаг"

-o каталог

Каталог, в который компилятор должен поместить выходные файлы. Если не указан, выходные файлы будут помещены в текущий рабочий каталог.

Затем, после компиляции, вы можете запустить свой код, либо с erl Эрланг В.М. или использование escript (который использует erl,

erl запускать код из скомпилированных модулей, и для этого ему нужно уметь находить скомпилированные модули *.ebin двоичные файлы. Для этого он использует путь к коду, который представляет собой список директоров, в которых он будет искать эти файлы. Этот список автоматически состоит из стандартных библиотечных каталогов, и, конечно, вы можете добавлять в него каталоги с собственным кодом с использованием -pa флаг.

-па Дир1 Дир2 ...

Добавляет указанные каталоги в начало пути кода, аналогично коду:add_pathsa/1. Смотрите код (3). В качестве альтернативы -pa, если к коду необходимо добавить несколько каталогов, а каталоги имеют общий родительский каталог, этот родительский каталог можно указать в переменной среды ERL_LIBS. Смотрите код (3).

В вашем случае это будет erl -pa ebinили включить бинарные файлы всех deps, которые вы можете использовать erl -pa ebin -pa deps/*/ebin,

Точно такие же параметры используются во второй строке вашего сценария. За исключением * символ, который не будет расширяться, как в оболочке. В escript вы должны указать пути к каждой зависимости отдельно. Но идея включения -pa ebin остается точно таким же.

Для автоматизации и стандартизации этого процесса такие инструменты, как rebar и erlang.mk, где они были созданы (я бы порекомендовал позже). Их использование должно немного помочь вам в вашем рабочем процессе.

Другие вопросы по тегам