【问题标题】:Program Seems to Terminate Early计划似乎提前终止
【发布时间】:2017-03-06 02:59:26
【问题描述】:

我觉得这是非常简单的问题之一,我只是不了解该语言。但是我正在尝试学习 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 的所有数字。如果我只取消注释 @987654324 @line,我一直没有得到任何输出。

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

值得指出的是,我产生这种困惑的原因是我试图使用mix 编译一个更大的项目,当程序似乎开始时,完成它的一小部分工作,然后终止因为mix 显然会在一段时间后停止运行。所以我也不确定运行 Elixir 程序的惯用方式是什么,因为mix 似乎在不久之后就会终止它。

【问题讨论】:

    标签: concurrency elixir terminate


    【解决方案1】:

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

    因此,当您启动程序时,“主”进程开始执行一些工作。在您的情况下,它会创建一个新进程(我们称之为“进程 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 也是一个构建工具,并不是你运行应用程序的真正方式(虽然,你可以)。同样,在不知道您正在尝试做什么或查看您的代码的情况下,我无法提供更多信息。

    【讨论】:

    • 非常感谢。我对mix 的问题直接源于我对 Elixir 流程与其他语言所称流程的误解。
    • 另一种可能的解决方案是使用elixir --ho-halt foo.ex 运行程序,“执行后不会停止Erlang VM”。然后可以按两次 Ctrl-C 退出程序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 2020-02-19
    • 1970-01-01
    • 2021-01-09
    • 2015-08-13
    • 2019-11-22
    • 1970-01-01
    相关资源
    最近更新 更多