Erlang工作过程



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

我当前的步骤是:

  1. 创建服务器过程。
  2. 产生工人。
  3. 向工人发送一些工作以基于客户的输入。(这是我困惑的地方(
  4. 将数据从工人发送回客户。

这是一些示例代码。

-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.

您如何做到这一点,以便看到从工人那里收到的数据并可以将其发送给客户?

我可以看到您在服务器过程中有两个主要问题:

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

将消息发送给工人

您从L8 -L10中的以下代码行不正确。

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

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

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

由于getNameFromDataBase期望{name, Name},仅将Name发送到Worker将不会被注意到。这应该更改为

Worker ! {name, Name}

发送结果(lastName(到客户端

在L10上发送From ! LastName是没有意义的,因为您尚未收到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编译选项。仅导出必要的功能以实现良好的封装。

您将从接收的{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的第三个参数(。另外,如果您创建工人只是要立即发送一条消息,那么您也可以将其内容作为参数传递;我没有在这里进行此更改,以使看到主要更改变得更容易。

另外,您可以在服务器状态中存储与Worker相对应的From(参数到server()(。

最新更新