问题描述
假设您有一个 OTP 进程,您希望同步等待其完成(其中“完成”可能是正常退出或崩溃、停止等)。
进一步假设,出于业务原因,您不能使用 Task.async/1
或相关的 Task
实用程序生成此进程 - 它必须是不依赖于 Task.await/2
的“正常”进程。
是否有比简单地间歇性轮询 Process.alive?/1
更好的方法?这让我印象深刻,因为这种事情可能有一个既定的模式,但对于我的生活,我找不到它。
def await(pid,timeout) when timeout <= 0 do
if Process.alive?(pid) do
Process.exit(pid,:kill) # (or however you want to handle timeouts)
end
end
@await_sleep_ms 500
def await(pid,timeout) do
# Is there a better way to do this?
if Process.alive?(pid) do
:timer.sleep(@await_sleep_ms)
await(pid,subtract_timeout(timeout,@await_sleep_ms))
end
end
解决方法
Process.monitor/1
函数从调用进程监视给定进程。将此与 receive
结合使用,您可以对您的流程邮箱做出反应。
defmodule Await do
def spawn do
Kernel.spawn(fn -> :timer.sleep(2000) end)
end
def await_down(pid) do
ref = Process.monitor(pid)
receive do
{:DOWN,^ref,:process,^pid,_reason} = message -> {:ok,message}
after
3000 -> {:error,:timeout}
end
end
end
pid = Await.spawn()
# => #PID<0.332.0>
Await.await_down(pid)
# => {:ok,{:DOWN,#Reference<0.4083290149.3661365255.180715>,#PID<0.332.0>,:normal}}
注意接收块内的模式匹配,以确保消息不仅来自您的进程,而且来自特定的监控。
,看起来 Process.monitor/1
可能正是您要找的?文档中的示例:
verifiedTeacher