Erlang:生成一个进程并等待终止而不使用`receive`

时间:2016-08-30 03:53:34

标签: erlang

在Erlang中,我可以调用一些函数f(BIF与否),其作用是生成一个进程,运行我提供的函数argf,并且直到{才“返回” {1}}已“返回”,并且在不使用argf子句的情况下执行此操作(原因是receive将在gen_server中调用,我不想污染gen_server的邮箱)。

一个片段看起来像这样:

f

3 个答案:

答案 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/2erlang: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.