首先,我对Elixir很新,所以这可能是一个误入歧途的问题
我有一个启动两个进程的函数。
第一个进程使用erlang:fs库来监视文件更改的目录,然后向第二个进程发送消息。
第二个进程等待一条消息,指出目录中的文件已更改,当它收到消息时,会运行一个重新生成HTML报告的函数(它是一张发票)。
看起来像这样:
def run_report_daemon(line_item_dir) do
if Process.whereis(:html_daemon) == nil do
spawn(HTMLInvoiceDaemon, :run_daemon, [line_item_dir])
|> Process.register(:html_daemon)
end
if Process.whereis(:file_watcher) == nil do
:fs.start_link(:file_watcher, Path.absname(line_item_dir))
end
Process.sleep(1000)
run_report_daemon(line_item_dir)
end
这“有效”,但困扰我的是“睡眠”和递归呼叫。
我的问题:是否有更好的方法来保持包含生成我的进程的函数的进程。如果没有递归调用和睡眠,它就会死掉并带走其他进程。通过递归调用和无睡眠,它消耗了大量处理器资源,因为它可以非常快速地循环。
if块是必需的,否则会反复生成并注册进程。
我想过使用Supervisor,但后来我不确定如何在主管下启动:fs进程,即使在这种情况下我也需要保持启动进程。
我怀疑我的问题是因为对Elixir中“正确做事方式”的基本误解。
(注意:我可以在没有这样的产卵过程的情况下完成整个过程,但这是一个学习练习)
答案 0 :(得分:1)
我可能会做这样的事情
请注意,如果其中任何一个崩溃,主管将重新启动它,我们将以正确的状态结束,其中有一个InvoiceDaemon
进程和一个InvoiceDaemon
进程,并且FSWatch
进程将监听rest_for_one
进程。
策略为InvoiceDaemon
,如果FSWatch
进程终止,它将重新启动InvoiceDaemon
进程。这样可以防止FSWatch
进程订阅不再存在的InvoiceDaemon
进程。如果FSWatch
崩溃,则无需重新启动InvoiceDaemon
进程,因为当defmodule Thing do
use Supervisor
# Wraps the :fs.start_link
# thing in a process and goes to sleep
defmodule FSWatch do
def start_link(target_dir) do
watcher = spawn_link(fn ->
IO.puts "Watching #{target_dir}"
:fs.start_link(:file_watcher, target_dir)
:timer.sleep(:infinity)
end)
{:ok, watcher}
end
end
# Subscribe to the file watcher and then listen
# forever
defmodule InvoiceDaemon do
def start_link do
daemon = spawn_link(fn ->
:fs.subscribe(:file_watcher, "/path")
run()
end)
{:ok, daemon}
end
defp run do
receive do
{_, {:fs, file_event}, path} ->
IO.puts "Got a file event #{inspect path}"
run()
e ->
IO.puts "unexpected event #{inspect e}"
run()
end
end
end
def start_link do
target_dir = "/foo/bar"
children = [
worker(FSWatch, [target_dir]),
worker(InvoiceDaemon, [])
]
IO.inspect self
Supervisor.start_link(children, strategy: :rest_for_one)
end
end
Thing.start_link
:timer.sleep(:infinity)
重新启动时,它将重新订阅然后永久运行。
gc()
答案 1 :(得分:0)
如果您不打算使用主管,这是正确的方法,您可以使用链接/监视器来处理这些过程。
而不是睡眠/递归调用,您链接/监视这些进程。然后等待一条关闭消息,当它们中的任何一个死亡时发送给你。
好处是你阻止接收,所以没有资源消耗。
实际上,这是主管的基础,如果可能的话我会推荐一个。
更多阅读 http://elixir-lang.org/docs/stable/elixir/Process.html
查看spawn_link和spawn_monitor函数。