Erlang:从共享队列推拉

Erlang:从共享队列推拉,erlang,Erlang,我需要维护一个共享队列,在那里我可以推送数据,如果队列不是空的,一个单独的线程将定期检查并从队列中提取数据。我提出了下面的解决方案,可以将数据发送到流程,并将其添加到列表中。但是,是否有更干净/更简单的解决方案 我不知道如何从下面的代码中提取数据 -module(abc). -export(queue/0). queue() -> receive {push, Xmpp} -> io:format("Push"),

我需要维护一个共享队列,在那里我可以推送数据,如果队列不是空的,一个单独的线程将定期检查并从队列中提取数据。我提出了下面的解决方案,可以将数据发送到流程,并将其添加到列表中。但是,是否有更干净/更简单的解决方案

我不知道如何从下面的代码中提取数据

-module(abc).
-export(queue/0).
queue() ->
    receive
        {push, Xmpp} ->
            io:format("Push"),
            queue(Xmpp);
        {pull} ->
            io:format("pull"),
            queue()
    end.

queue(E) ->
    receive
        {push, Xmpp} ->
            io:format("Push ~w",[E]),
            E1 = lists:append([E],[Xmpp]),
            queue(E1);
        {reset} ->
            queue([])
    end.

代码可能不会完全按照您编写的方式执行。当您从
receive
块(
queue(Xmpp);
第7行)调用
queue/1
时,
queue/1
将触发,然后等待消息。由于这不是在单独的进程中生成的,
queue/0
将被阻止(因为
queue/1
正在等待一条从未发送过的消息)

而且,
queue/0
永远不会将任何内容发送回发送消息的进程。它无法将数据返回给发件人

以下操作将起作用(您需要向
队列/0
返回的pid发送消息)


这是Erlang中简单解决方案的一个问题。大多数情况下,您将要编程的每个erlang模块都像一个服务器,它需要消息并会响应,您可以有0台、1台或多台服务器运行相同的erlang模块代码。同时,您将在客户端的同一模块中进行编程,这是一种向服务器发送消息的简单方法,无需知道服务器期望的所有消息格式,而是使用函数,因此不必执行类似的操作

Server ! {put, Value},
receive 
    {Server, {ok, Value}} ->
        everything_ok;
    {Server, {error, Reason}} ->
        handle_error
end,
你最终会做这样的事情

my_module:put(Server, Value).
因此,您可以使用以下代码在erlang中创建服务器进程:

-module(abc).
-export([start/0, put/2, pop/1, reset/1, is_empty/1, loop/1]).

%% Client

start() ->
    spawn(?MODULE, loop, [[]]).

put(Pid, Item) ->
    Pid ! {self(), {put, Item}},
    receive
        {Pid, {ok, Item}} ->
            Item;
        {Pid, {error, Reason}} ->
            {error, Reason}
    after 500 ->
            timeout
    end.

pop(Pid) ->
    Pid ! {self(), {pop}},
    receive
        {Pid, {ok, Item}} ->
            Item;
        {Pid, {error, Reason}} ->
            {error, Reason}
    after 500 ->
            timeout
    end.

reset(Pid) ->
    Pid ! {self(), {reset}},
    receive
        {Pid, {ok}} ->
            ok;
        _ ->
            error
    after 500 ->
            timeout
    end.

is_empty(Pid) ->
    Pid ! {self(), {is_empty}},
    receive
        {Pid, {true}} ->
            true;
        {Pid, {false}} ->
            false;
        _ ->
            error
    after 500 ->
            timeout
    end.

%% Server

loop(Queue) ->
    receive
        {From, {put, Item}} when is_pid(From) ->      
            From ! {self(), {ok, Item}},
            loop(Queue ++ [Item]);
        {From, {pop}} when is_pid(From) ->
            case Queue of
                [] -> 
                    From ! {self(), {error, empty}},
                    loop(Queue);
                [H|T] ->
                    From ! {self(), {ok, H}},
                    loop(T)
            end;
        {From, {reset}} when is_pid(From) ->
            From ! {self(), {ok}},
            loop([]);
        {From, {is_empty}} when is_pid(From) ->
            case Queue of
                [] ->
                    From ! {self(), {true}},
                    loop(Queue);
                _ ->
                    From ! {self(), {false}},
                    loop(Queue)
            end;
        _ ->
            loop(Queue)
    end.
您结束编写要使用的代码也很简单:

(emacs@rorra)1> c("/Users/rorra/abc", [{outdir, "/Users/rorra/"}]).     
{ok,abc}      

(emacs@rorra)2> Q = abc:start().       
<0.44.0>

(emacs@rorra)3> abc:is_empty(Q).       
true

(emacs@rorra)4> abc:pop(Q).       
{error,empty}

(emacs@rorra)5> abc:put(Q, 23).       
23

(emacs@rorra)6> abc:is_empty(Q).       
false

(emacs@rorra)7> abc:pop(Q).       
23

(emacs@rorra)8> abc:pop(Q).       
{error,empty}

(emacs@rorra)9> abc:put(Q, 23).       
23

(emacs@rorra)10> abc:put(Q, 50).       
50

(emacs@rorra)11> abc:reset(Q).       
ok

(emacs@rorra)12> abc:is_empty(Q).       
true
(emacs@rorra)1> c(“/Users/rorra/abc”,[{outdir,“/Users/rorra/”}])。
{好的,abc}
(emacs@rorra)2> Q=abc:start()。
(emacs@rorra)3> abc:is_为空(Q)。
真的
(emacs@rorra)4> abc:pop(Q)。
{错误,空}
(emacs@rorra)5> abc:put(Q,23)。
23
(emacs@rorra)6> abc:is_为空(Q)。
假的
(emacs@rorra)7> abc:pop(Q)。
23
(emacs@rorra)8> abc:pop(Q)。
{错误,空}
(emacs@rorra)9> abc:put(Q,23)。
23
(emacs@rorra)10> abc:put(Q,50)。
50
(emacs@rorra)11> abc:重置(Q)。
好啊
(emacs@rorra)12> abc:is_为空(Q)。
真的
最后,为了避免所有重复的代码,您使用OTP并为其编写gen_服务器

我假设您正在自己构建一个队列进行学习,否则Erlang已经有了一个很好的队列实现:

和源代码:


嘿,谢谢你的详细解释。我来检查erlang队列。
(emacs@rorra)1> c("/Users/rorra/abc", [{outdir, "/Users/rorra/"}]).     
{ok,abc}      

(emacs@rorra)2> Q = abc:start().       
<0.44.0>

(emacs@rorra)3> abc:is_empty(Q).       
true

(emacs@rorra)4> abc:pop(Q).       
{error,empty}

(emacs@rorra)5> abc:put(Q, 23).       
23

(emacs@rorra)6> abc:is_empty(Q).       
false

(emacs@rorra)7> abc:pop(Q).       
23

(emacs@rorra)8> abc:pop(Q).       
{error,empty}

(emacs@rorra)9> abc:put(Q, 23).       
23

(emacs@rorra)10> abc:put(Q, 50).       
50

(emacs@rorra)11> abc:reset(Q).       
ok

(emacs@rorra)12> abc:is_empty(Q).       
true