计划似乎提前终止

时间:2017-03-06 02:59:26

标签: concurrency elixir terminate

我觉得这是一个非常简单的问题,其中有一些我对语言不了解的东西。但是我正在努力学习Elixir,而我的程序并没有完全运行。我在这里有一个很小的例子。

defmodule Foo do
  def run(0) do
    IO.puts("0")
  end
  def run(n) do
    IO.puts(to_string n)
    run(n - 1)
  end
  def go do
    run(100)
  end
end

# Foo.go
# spawn &Foo.go/0

现在,如果我取消注释底部的Foo.go行并使用elixir minimal.exs运行它,那么我得到预期的输出,这是从100到0的所有数字。如果我取消注释只有spawn &Foo.go/0行,我一直都没有输出。

但是,如果我取消注释两行并运行程序,我会在程序终止之前将数字从100到0(从第一行开始),然后是前几个数字(通常大约100到96左右)原因。所以我真的不知道是什么导致进程在随机点终止。

值得指出的是,这种混乱的原因是我试图使用mix编译一个更大的项目,当程序似乎开始时,做了一小部分工作,并且然后终止,因为mix显然在一点之后停止运行。所以我不确定运行Elixir程序的惯用方法是什么,因为mix似乎在一段时间后终止它。

1 个答案:

答案 0 :(得分:3)

spawn/1将创建一个新进程来运行该函数。虽然它们不一样,但您可以将Erlang / Elixir进程想象成大多数其他语言中的线程。

所以,当你开始你的程序时," main"过程得做一些工作。在您的情况下,它会创建一个新进程(让我们调用它"进程A")将数字从100输出到0.但是,问题是spawn/1不会阻塞。意思是"主要"过程将继续执行而不是等待过程A"回来。

所以正在发生的事情是你的"主要"进程正在完成执行,结束整个程序。这对我曾经使用的每种语言都是正常的。

如果你想在不同的过程中产生一些工作,并确保它在结束你的程序之前完成执行,你有几个不同的选择。

您可以使用Task模块。根据这一点,应该有所作为。

task = Task.async(&Foo.go/0)
Task.await(task)

您可以明确send and receive条消息

defmodule Foo do
  def run(0, pid) do
    IO.puts("0")

    # This will send the message back to the "main" thread upon completion.
    send pid, {:done, self()}
  end
  def run(n, pid) do
    IO.puts(to_string n)
    run(n - 1, pid)
  end

  # We now pass along the pid of the "main" thread into the go function.
  def go(pid) do
    run(100, pid)
  end
end

# Use spawn/3 instead so we can pass in the "main" process pid.
pid = spawn(Foo, :go, [self()])

# This will block until it receives a message matching this pattern.
receive do
  # The ^ is the pin operator. It ensures that we match against the same pid as before.
  {:done, ^pid} -> :done
end

还有其他方法可以实现这一目标。不幸的是,如果不了解您要解决的问题,我只能提出基本建议。

尽管如此,mix不会随意停止正在运行的程序。无论出于何种原因,"主要"进程必须已完成执行。另外mix是一个构建工具,不是你应该运行应用程序的方式(尽管如此,你可以)。再一次,在不知道你想要做什么或看到你的代码的情况下,我不能给你更多的东西。