在我的程序中,读取CSV文件中的每一行之后,都会产生一个新的过程来下载该图像并将其保存到文件系统:
defmodule Downloader.CLI do
alias Downloader.Parser
alias Downloader.Getter
def main(_args \\ []) do
Enum.map(Parser.run, fn(line) ->
line -> handle_download(line)
end)
end
defp handle_download({ :ok, %{ "image_id" => image_id } }) do
pid = spawn(Getter, :run, [])
send(pid, {self(), image_id})
receive do
:ok -> nil
err -> IO.inspect(err)
end
end
end
如果此CSV文件包含1000张图像,则将在VM中创建1000个不同的e剂工艺。但是,如果这些进程中只有一个抛出异常,则其他任何进程都不会继续。也就是说,可执行文件不会冻结,但是不会下载其他图像。
为什么会这样?如果其他进程彼此独立,为什么它们不能继续执行?我觉得自己缺少一些简单的东西,但在其他任何地方都找不到。
答案 0 :(得分:5)
问题:receive do
等待一条永远不会到达的消息。
这是逐步发生的事情:
spawn
创建流程pid
pid
崩溃,然后将消息发送回初始进程Enum.map
将不会启动。为说明此问题,请在iex中运行以下脚本:
Process.send_after(self(), "Hi Luis", 30000)
receive do
mess -> IO.inspect mess
end
您只会在30秒后收到"Hi Luis"
,在那30秒内,您的iex将等待消息,因为它是同步的。
解决方案::确保始终发送回一条消息,例如使用Process.monitor/1
或Supervisor
。
defmodule Downloader.CLI do
alias Downloader.Parser
alias Downloader.Getter
def main(_args \\ []) do
Enum.map(Parser.run, fn(line) ->
line -> handle_download(line)
end)
end
defp handle_download({ :ok, %{ "image_id" => image_id } }) do
pid = spawn(Getter, :run, [])
Process.monitor(pid)
send(pid, {self(), image_id})
receive do
:ok -> nil
err -> IO.inspect(err)
end
flush # To avoid having a Down message ending prematurely next download
end
end