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

Erlang:生成进程并等待终止,而不使用'receive'`,erlang,Erlang,在Erlang中,我是否可以调用某个函数f(BIF或not),该函数的任务是生成一个进程,运行我提供的函数argf,直到argf已“返回”才“返回”,并且在不使用receive子句的情况下执行此操作(原因是f将在gen_服务器中调用,我不想污染gen_服务器的邮箱) 代码段如下所示: %% some code omitted ... F = fun() -> blah, blah, timer:sleep(10000) end, f(F), %% like `spawn(F), but d

在Erlang中,我是否可以调用某个函数
f
(BIF或not),该函数的任务是生成一个进程,运行我提供的函数
argf
,直到
argf
已“返回”才“返回”,并且在不使用
receive
子句的情况下执行此操作(原因是
f
将在gen_服务器中调用,我不想污染gen_服务器的邮箱)

代码段如下所示:

%% some code omitted ...
F = fun() -> blah, blah, timer:sleep(10000) end,
f(F), %% like `spawn(F), but doesn't return until 10 seconds has passed`
%% ...

<> P>进程间通信的唯一方法是消息传递(当然,您可以考虑在ETS或文件中轮询特定的密钥,但我不喜欢这样)。 如果在f/1中使用spawn_monitor函数启动f进程,然后接收块仅与来自此监视器的可能系统消息相匹配:

f(F) ->
    {_Pid, MonitorRef} = spawn_monitor(F),    
    receive
        {_Tag, MonitorRef, _Type, _Object, _Info} -> ok
    end.

你不会弄乱你的GeNyServer邮箱。这个例子是最小的代码,你可以添加一个超时(固定或参数),在正常或错误完成上执行一些代码……/P> < P>进程之间的唯一通信方式是消息传递(当然,你可以考虑在ETS或文件中轮询一个特定的键,但是我不喜欢这个)。 如果在f/1中使用spawn_monitor函数启动f进程,然后接收块仅与来自此监视器的可能系统消息相匹配:

f(F) ->
    {_Pid, MonitorRef} = spawn_monitor(F),    
    receive
        {_Tag, MonitorRef, _Type, _Object, _Info} -> ok
    end.
您不会弄乱gen_服务器邮箱。示例是最小代码,您可以添加超时(固定或参数),在正常或错误完成时执行一些代码…

您不会“污染”如果您在从呼叫或强制转换返回之前生成+等待消息,则会出现gen_服务器邮箱。更严重的问题是,您可能会在等待其他进程终止时阻塞gen_服务器。解决此问题的方法是不显式等待,而是从呼叫/强制转换返回,然后在完成消息到达时返回在
handle_info/2
中处理它,然后执行必要的操作

如果繁殖是在
handle\u调用中完成的,并且您希望返回该进程的“结果”,那么您可以延迟将值从处理进程终止消息的
handle\u info
返回到原始调用

请注意,无论您如何操作,gen_server:call都有一个超时值,可以是隐式的,也可以是显式的,如果没有返回响应,则会在调用过程中生成错误。

您不会“污染”如果您在从呼叫或强制转换返回之前生成+等待消息,则会出现gen_服务器邮箱。更严重的问题是,您可能会在等待其他进程终止时阻塞gen_服务器。解决此问题的方法是不显式等待,而是从呼叫/强制转换返回,然后在完成消息到达时返回在
handle_info/2
中处理它,然后执行必要的操作

如果繁殖是在
handle\u调用中完成的,并且您希望返回该进程的“结果”,那么您可以延迟将值从处理进程终止消息的
handle\u info
返回到原始调用


请注意,无论您如何操作,gen_server:call都有一个超时值,可以是隐式的,也可以是显式的,如果没有返回响应,则会在调用过程中生成错误。

在Erlang VM空间中与进程通信的主要方式是使用或函数(别名
)传递消息。但是您可以“黑客”Erlang并使用多种方式通过进程进行通信

您可以使用来传递进程的状态,它主要用于进程即将死亡、结束或出现错误(异常或抛出)的情况

您可以使用,这与类似,只是消息直接进入流程邮箱

您也可以破解Erlang,并使用一些内部方法(共享
ETS
/
DETS
/
Mnesia
表)或使用外部方法(数据库或其他类似的东西)。这显然不是推荐的方法,也可以“摧毁”Erlang哲学……但您可以做到

您的问题似乎可以通过行为来解决。
supervisor
支持多种方式来控制受监督的流程:

  • one_for_one
    :如果一个子进程终止并要重新启动,则只影响该子进程。这是默认的重新启动策略
  • one_for_all
    :如果一个子进程终止并要重新启动,则所有其他子进程都会终止,然后所有子进程都会重新启动
  • rest\u for_one
    :如果有一个子进程终止并要重新启动,则终止子进程的“剩余”部分(即,在启动顺序中终止的子进程之后的子进程)。然后,终止的子进程及其后的所有子进程都将重新启动
  • simple\u one\u for\u one
    :一个simplified one\u for\u one supervisor,其中所有子进程都动态添加相同进程类型的实例,即运行相同的代码
您还可以从零开始修改或创建自己的主管策略,或基于

总之,您需要一个等待一个或多个终止进程的进程。OTP本机支持此行为,但您也可以创建自己的模型。为此,您需要使用缓存或数据库共享每个已启动进程的状态,或者在生成进程时共享状态。类似于:

Fun=Fun
MyFun(父进程,{result,Data})
什么时候是pid(父进程)->
ParentProcess!{self(),Data};
MyFun(ParentProcess,MyData)
什么时候是pid(父进程)->
%做点什么
MyFun(父进程,MyData2)结束。
繁殖(fun()->fun(self(),InitData)结束)。
编辑:忘记添加没有
发送
/
接收
的示例。我使用
ETS
表存储lambda函数的每个结果。此
ETS
表是在生成此过程时设置的。