Erlang工人流程

时间:2018-04-05 01:20:27

标签: erlang message message-passing

我对Erlang很新,但是我一直在尝试创建一个简单的客户端服务器实现。服务器会假设创建工作进程以在“数据库”中执行“繁重的工作”,然后将计算的值返回给客户端。

我目前的步骤是:

  1. 创建服务器进程。
  2. 产生一名工人。
  3. 根据客户输入向工作人员发送一些工作。 (这是我困惑的地方)
  4. 将工作人员的数据发送回客户端。
  5. 以下是一些示例代码。

    -module(server).
    -compile(export_all).
    
    server() ->
        receive
            {From, {client, Name}} ->
                io:format("Server has received request for ~p from ~p~n", [Name, From]),
                Worker = spawn(server, getNameFromDataBase(self()),[]),
                Worker ! Name,
                From ! LastName,%%data returned from worker
                server();
            {database, LastName} ->
                Data = LastName,
                server()
        end.
    
    
    getNameFromDataBase(Server_Address) ->
        receive
            {name, Name} ->
                timer:sleep(5000), %doing difficult work!
                Server_Address ! {database, "Johnson"}
        end.
    
    
    
    client(Server_Address) ->
        Server_Address ! {self(), {client, "Jim"}},
        receive
                {server, LastName} ->
                    io:format("Server got person's last name~p~n", LastName)
        end.
    

    如何制作以便从工作人员那里收到的数据能够被发送到客户端?

2 个答案:

答案 0 :(得分:3)

我可以看到服务器进程有两个主要问题:

  1. 从服务器向数据库工作者发送消息。
  2. 将服务器从工作人员收到的消息发送回客户端。
  3. 向工作人员发送消息

    以下L8 - L10代码行不正确。

    %% ...
    Worker = spawn(server, getNameFromDataBase(self()), []),
    Worker ! Name,                                           
    From ! LastName,                   
    %% ...
    

    要将函数生成为进程,必须在spawn/3的第三个参数中为函数提供任何参数作为列表成员,而不是直接调用函数。

    Worker = spawn(server, getNameFromDataBase, [self()]),
    

    Name期待Worker,因此只会getNameFromDataBase{name, Name}发送,但不会被注意到。这应该改为

    Worker ! {name, Name}
    

    将结果(LastName)发送到客户端

    由于您尚未收到From ! LastName,因此在L10上发送LastName没有意义。当服务器从工作程序收到{database, LastName}时,应将其移动到第二个匹配表达式。 此外,client预计{server, LastName},而非LastName。所以应该是From ! {server, LastName}

    但是,有一个问题。您无法访问该范围内的From,因为它从未被定义过。

    %% ...
    {database, LastName} ->
        From ! {server, LastName},      % `From` is not defined
        server()
    %% ...
    

    在不必更改消息元组的情况下,您可能想要做的是定义另一个server/1函数,如下所示:

    server(ClientPID) ->
        receive
            {_, LastName} ->
                ClientPID ! {server, LastName},
                server()
        end.
    

    并从server/0

    调用此方法
    server() ->
        receive
            {From, {client, Name}} ->
                io:format("Server has received request for ~p from ~p~n", [Name, From]),
                Worker = spawn(?MODULE, getNameFromDataBase, [self()]),
                Worker ! {name, Name},
                server(From)      % call `server/1` with the client's PID
        end.
    

    最后,要包装所有内容,如果还没有,请创建一个启动函数来生成serverclient进程。这是完成的代码:

    server() ->
        receive
            {From, {client, Name}} ->
                io:format("Server has received request for ~p from ~p~n", [Name, From]),
                Worker = spawn(?MODULE, getNameFromDataBase, [self()]),
                Worker ! {name, Name},
                server(From)
        end.
    
    server(ClientPID) ->
        receive
            {_, LastName} ->
                ClientPID ! {server, LastName},
                server()
        end.
    
    getNameFromDataBase(ServerAddr) ->
        receive
            {name, Name} ->
                io:format("worker received ~p~n",[Name]),
                timer:sleep(5000),
                ServerAddr ! {database, "Johnson"}
        end.
    
    client(ServerPID) ->
        ServerPID ! {self(),{client, "Jim"}},
        receive
            {server, LastName} ->
                io:format("Client got person's last name ~p from Server ~n", [LastName])
        end.
    
    run() ->
        ServerPID = spawn(?MODULE, server, []),
        spawn(?MODULE, client, [ServerPID]).
    

    最后提示:不要使用export_all编译选项。只导出必要的功能以实现良好的封装。

答案 1 :(得分:1)

您将收到来自收件人{database, LastName} ->分支中的工作人员的消息。只需在消息本身中包含处理它所需的信息:

server() ->
    receive
        {From, {client, Name}} ->
            io:format("Server has received request for ~p from ~p~n", [Name, From]),
            Worker = spawn(server, getNameFromDataBase, [self()]),
            Worker ! {name, From, Name},
            server();
        {database, From, LastName} ->
            From ! LastName,
            server()
    end.

getNameFromDataBase(Server_Address) ->
    receive
        {name, From, Name} ->
            timer:sleep(5000), %doing difficult work!
            Server_Address ! {database, From, "Johnson"}
    end.

请注意,参数需要在列表中传递(spawn的第三个参数)。此外,如果您创建工作程序只是为了立即发送单个消息,您也可以将其内容作为参数传递;我没有在这里做这个改变,以便更容易看到主要的变化。

或者,您可以将From对应的Worker存储在服务器状态(server()的参数)。