无法向生成的Erlang进程发送任何内容

时间:2014-11-06 20:05:40

标签: erlang actor erlang-escript

我有以下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

此代码不起作用。看起来像spawn不起作用。

如果我从main运行它,我的其余代码工作,函数发送和验证正常工作(我已经评论了它)。我做错了什么?

对不起,也许这是一个愚蠢的问题,但我是erlang的初学者。我试过在互联网和书籍上搜索答案,但我失败了......

1 个答案:

答案 0 :(得分:3)

问题实际上不是在spawn中,而是在模块/ escript混乱中。

简而言之,即使您使用-module()指令,escript文件也不是真正的模块,而不是Erlang VM。它们被解释,并且根本没有编译,并且它们不能被像“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.

或者您可以在没有escript的情况下启动此模块,并使用-run这样的标记

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

关于编译问题

编辑

使用erlc command编译模块。只编译使用erlc rmq.erl,这将在当前目录中生成rmq.beam文件。但惯例是将所有源文件保存在src目录中,所有编译文件保存在ebin目录中,并且运行脚本之类的东西可以放在顶层目录中。这样的事情:

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

假设您从project目录运行所有shell命令,要编译来自src的所有文件并将.beam二进制文件放在ebin中使用erlc src/rmq.erl -o ebin,或erlc src/* -o ebin在文档中,您可以找到-o flag“

的说明
  

-o目录

     

编译器应放置输出文件的目录。如果未指定,则输出文件将放在当前工作目录中。

然后,在编译之后,您可以使用erl Erlang VM或使用escript来运行您的代码(使用erl时会使用erl

*.ebin从已编译的模块运行代码,为此,他需要能够找到那些已编译的-pa二进制文件。为此他使用代码路径,这是他将搜索这些文件的导演列表。此列表自动包含标准库目录,当然您可以使用erl -pa ebin标志将自己的代码添加到目录中。

  

-pa Dir1 Dir2 ......

     

将指定的目录添加到代码路径的开头,类似于代码:add_pathsa / 1。见代码(3)。作为-pa的替代方案,如果要为代码添加多个目录并且目录具有公共父目录,则可以在ERL_LIBS环境变量中指定该父目录。见代码(3)。

在您的情况下,它将是erl -pa ebin -pa deps/*/ebin,或者包含您可以使用*的所有代码的二进制文件。

在您的escript的第二行中使用了完全相同的选项。除-pa ebin字符外,它不会像在shell中那样展开。在escript中,您必须分别提供每个依赖项的路径。但是包含{{1}}的想法保持不变。

自动化和标准化此过程工具,例如创建的rebarerlang.mk(我建议稍后使用)。使用它们可以帮助您完成工作流程。