在Erlang中,我可以调用一些函数f
(BIF与否),其作用是生成一个进程,运行我提供的函数argf
,并且直到{才“返回” {1}}已“返回”,并且在不使用argf
子句的情况下执行此操作(原因是receive
将在gen_server中调用,我不想污染gen_server的邮箱)。
一个片段看起来像这样:
f
答案 0 :(得分:2)
进程之间进行通信的唯一方法是传递消息(当然你可以考虑在ets或文件中查询特定的密钥,但我不喜欢这样)。
如果在f / 1中使用spawn_monitor函数来启动F进程,然后使接收块仅匹配来自此监视器的可能系统消息:
f(F) ->
{_Pid, MonitorRef} = spawn_monitor(F),
receive
{_Tag, MonitorRef, _Type, _Object, _Info} -> ok
end.
你不会弄乱你的gen_server邮箱。示例是最小代码,您可以添加超时(固定或参数),在正常或错误完成时执行一些代码...
答案 1 :(得分:1)
你不会污染"污染" gen_servers邮箱,如果你在从调用或强制转换返回之前生成+等待消息。更严重的问题可能是您在等待其他进程终止时阻塞gen_server。解决这个问题的方法是不要显式等待,而是从call / cast返回,然后当完成消息到达时,在handle_info/2
处理它,然后执行必要的操作。
如果产生在handle_call
中完成,并且您想要返回"结果"然后,您可以延迟将值返回到处理进程终止消息的handle_info
中的原始调用。
请注意,无论你这样做,gen_server:call
都有一个超时值,无论是隐式还是显式,如果没有返回任何回复,它会在调用过程中产生错误。
答案 2 :(得分:1)
与Erlang VM空间中的进程通信的主要方式是使用erlang:send/2
或erlang:send/3
函数(别名!
)传递消息。但你可以" hack" Erlang并使用多种方式进行流程通信。
您可以使用erlang:link/1
来传达流程的统计信息,主要用于您的流程正在死亡或已结束或出现问题(异常或抛出)。
您可以使用erlang:monitor/2
,这类似于erlang:link/1
,但邮件会直接进入流程邮箱。
你也可以破解Erlang,并使用一些内部方式(共享ETS
/ DETS
/ Mnesia
表)或使用外部方法(数据库或其他类似的东西)。显然不推荐这样做"销毁" Erlang哲学......但你可以做到。
看来你的问题可以通过supervisor
行为来解决。 supervisor
支持许多strategies来控制受监督的流程:
one_for_one
:如果一个子进程终止并且要重新启动,则只有该子进程受到影响。这是默认的重启策略。one_for_all
:如果一个子进程终止并且要重新启动,则终止所有其他子进程,然后重新启动所有子进程。rest_for_one
:如果一个子进程终止并且要重新启动,那么“休息”将会重新启动。子进程(即,在启动顺序中终止子进程之后的子进程)终止。然后,重新启动已终止的子进程和所有子进程。simple_one_for_one
:简化的one_for_one主管,其中所有子进程都是动态添加相同进程类型的实例,即运行相同的代码。
您还可以从头开始或基于supervisor_bridge
修改或创建自己的主管策略。
因此,总而言之,您需要一个等待一个或多个终止过程的进程。 OTP本身支持此行为,但您也可以创建自己的模型。为此,您需要使用缓存或数据库或生成进程时共享每个已启动进程的状态。这样的事情:
Fun = fun
MyFun (ParentProcess, {result, Data})
when is_pid(ParentProcess) ->
ParentProcess ! {self(), Data};
MyFun (ParentProcess, MyData)
when is_pid(ParentProcess) ->
% do something
MyFun(ParentProcess, MyData2) end.
spawn(fun() -> Fun(self(), InitData) end).
编辑:忘记添加没有send
/ receive
的示例。我使用ETS
表来存储lambda函数的每个结果。当我们生成此进程时,将设置此ETS
表。要获得结果,我们可以从此表中选择数据。注意,行的键是进程的进程ID。
spawner(Ets, Fun, Args)
when is_integer(Ets),
is_function(Fun) ->
spawn(fun() -> Fun(Ets, Args) end).
Fun = fun
F(Ets, {result, Data}) ->
ets:insert(Ets, {self(), Data});
F(Ets, Data) ->
% do something here
Data2 = Data,
F(Ets, Data2) end.