在生成的Elixir进程崩溃后,不会生成其他进程

Lui*_*los 3 erlang elixir

在我的程序中,在读取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
Run Code Online (Sandbox Code Playgroud)

如果此CSV文件包含1000个图像,则VM中将创建1000个不同的elixir进程.如果这些进程中只有一个抛出异常,则不会继续其他进程.也就是说,可执行文件不会冻结,但不会下载其他图像.

为什么会这样?如果其他进程彼此独立,为什么不能继续执行?我想错过一些简单的东西,但我在其他任何地方都找不到它.

Nat*_*ert 5

问题:receive do等待永远不会到达的消息.

这是一步一步发生的事情:

  1. spawn 创造过程 pid
  2. pid在将消息发送回初始进程之前,进程崩溃
  3. 初始进程卡在接收函数中:它等待消息.并且只要没有发送消息,一切都被搁置.Enum.map下载后不会启动.

要说明此问题,请在iex中运行以下脚本:

Process.send_after(self(), "Hi Luis", 30000)
receive do
    mess -> IO.inspect mess
end
Run Code Online (Sandbox Code Playgroud)

您将"Hi Luis"在30秒后收到,在这30秒内,您的iex将等待一条消息,因为它是同步的.

解决方案:确保始终发回消息,例如使用Process.monitor/1或a 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
Run Code Online (Sandbox Code Playgroud)