Concurrency 程序似乎提前终止

Concurrency 程序似乎提前终止,concurrency,elixir,terminate,Concurrency,Elixir,Terminate,我觉得这是一个非常简单的问题,我对这门语言有些不理解。但我正在努力学习长生不老药,而我的程序并不是一直在运行。我这里有一个最小的例子 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/

我觉得这是一个非常简单的问题,我对这门语言有些不理解。但我正在努力学习长生不老药,而我的程序并不是一直在运行。我这里有一个最小的例子

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
似乎会在短时间内终止它。

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

因此,当你开始你的程序时,“主要”过程开始做一些工作。在您的例子中,它创建了一个新的进程(我们称之为“进程a”)来输出从100到0的数字。但是,问题是
spawn/1
不会阻塞。这意味着“主”进程将继续执行,而不是等待“进程A”返回

所以现在发生的是,您的“主”进程正在完成执行,从而结束整个程序。这对于我使用过的每种语言来说都是正常的

如果您想在不同的进程中产生一些工作,并确保它在结束程序之前完成执行,那么您有两个不同的选项

你可以使用这个模块。类似这样的东西应该会奏效

task = Task.async(&Foo.go/0)
Task.await(task)
您可以显式地发送消息

实现这一点还有其他方法。不幸的是,我对你试图解决的问题没有更多的了解,我只能提出一些基本的建议


综上所述,
mix
不会随意停止您正在运行的程序。无论出于何种原因,“主”流程必须已完成执行。另外,
mix
是一种构建工具,并不是您运行应用程序的真正方式(尽管您可以)。同样,在不知道您要做什么或没有看到您的代码的情况下,我不能给您更多的信息。

非常感谢。我的
mix
问题直接源于我对Elixir进程与其他语言所称进程的误解。另一种可能的解决方案是使用
Elixir--ho halt foo.ex
运行程序,它“在执行后不会停止Erlang VM”。然后可以键入Ctrl-C两次以退出程序。
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