Erlang 从Elixir进程打印到控制台

Erlang 从Elixir进程打印到控制台,erlang,elixir,Erlang,Elixir,所以,我开始玩Elixir,我想制作两个模块。提示您输入消息,然后将消息发送给另一个程序,该程序将确认收到消息,这将导致第一个程序打印出消息 嗯,我有很多问题 发送者如下: defmodule PracticeCaller do def start do spawn(&sloop/0) end def sloop do pid = :erlang.spawn(&PracticeServer.start/0)

所以,我开始玩Elixir,我想制作两个模块。提示您输入消息,然后将消息发送给另一个程序,该程序将确认收到消息,这将导致第一个程序打印出消息

嗯,我有很多问题

发送者如下:

defmodule PracticeCaller do
    def start do
        spawn(&sloop/0) 
    end

    def sloop do
        pid = :erlang.spawn(&PracticeServer.start/0)
        message = IO.gets "Enter a message:"
        send(pid, {self, message})
        receive do
            {_caller, reply} -> IO.puts "#{reply}"
        end
        sloop
    end
end
接收者在这里:

defmodule PracticeServer do
    def start do
        spawn(&loop/0)
    end

    defp loop do
        receive do
          {caller, "kill"} -> send(caller, {self, "Process Dead"})
                Process.exit(self, :kill)
            {caller, _} -> send(caller, {self, "Thank you for your message!"})      
        end

        loop    
    end

end
我的第一个问题是,当我启动发送方循环时,终端会提示我输入消息,但它不会打印收到的消息

其次,当我输入“kill”时,终端冻结,因为我不知道如何处理:kill响应

有没有关于解决这些问题的帮助?

第一个问题是:

pid = :erlang.spawn(&PracticeServer.start/0)
事实上,
PracticeServer.start/0
再次调用
spawn
。这意味着这里的
pid
不是指运行
PracticeServer.loop/0
的进程,而是指产生
PracticeServer.loop/0
并立即退出的进程

如果我改变:

pid = :erlang.spawn(&PracticeServer.start/0)
只是:

pid = PracticeServer.start
有些事情开始起作用:

Enter a message:hello
Thank you for your message!
Enter a message:world
Thank you for your message!
但是:

这是因为
IO.gets/1
包含尾随的换行符,这意味着
PracticeServer.loop/0
中的
{caller,“kill”}
模式从不匹配

可以通过更改以下内容来解决此问题:

message = IO.gets "Enter a message:"

现在:

另一个问题是,您当前正在泄漏进程。您不是重用生成的服务器,而是为每条消息生成一个新服务器。另外,处理可被“终止”的递归
receive
的惯用方法是在希望进程终止时不执行递归调用。以下是一些重构代码:

defmodule PracticeCaller do
  def start do
    spawn(fn -> loop(PracticeServer.start) end)
  end

  def loop(server) do
    message = IO.gets("Enter a message: ") |> String.trim_trailing
    send(server, {self, message})
    receive do
      {_caller, reply} ->
        IO.puts "#{reply}"
        # Only continue if process is not dead.
        # Comparing against strings is usually not idiomatic, you may want to
        # change that.
        if reply != "Process Dead" do
          loop(server)
        end
    end
  end
end

defmodule PracticeServer do
  def start do
    spawn(&loop/0)
  end

  def loop do
    receive do
      {caller, "kill"} ->
        send(caller, {self, "Process Dead"})
      {caller, _} ->
        send(caller, {self, "Thank you for your message!"})      
        loop    
    end
  end
end

PracticeCaller.start
:timer.sleep(:infinity)
请注意,即使在发送“kill”之后,这也不会停止VM。如果这只是一个脚本,那么当消息为“进程死机”时,您可以将
:erlang.halt
添加到
PracticeCaller.loop/1
,以立即停止VM。

第一个问题是:

pid = :erlang.spawn(&PracticeServer.start/0)
事实上,
PracticeServer.start/0
再次调用
spawn
。这意味着这里的
pid
不是指运行
PracticeServer.loop/0
的进程,而是指产生
PracticeServer.loop/0
并立即退出的进程

如果我改变:

pid = :erlang.spawn(&PracticeServer.start/0)
只是:

pid = PracticeServer.start
有些事情开始起作用:

Enter a message:hello
Thank you for your message!
Enter a message:world
Thank you for your message!
但是:

这是因为
IO.gets/1
包含尾随的换行符,这意味着
PracticeServer.loop/0
中的
{caller,“kill”}
模式从不匹配

可以通过更改以下内容来解决此问题:

message = IO.gets "Enter a message:"

现在:

另一个问题是,您当前正在泄漏进程。您不是重用生成的服务器,而是为每条消息生成一个新服务器。另外,处理可被“终止”的递归
receive
的惯用方法是在希望进程终止时不执行递归调用。以下是一些重构代码:

defmodule PracticeCaller do
  def start do
    spawn(fn -> loop(PracticeServer.start) end)
  end

  def loop(server) do
    message = IO.gets("Enter a message: ") |> String.trim_trailing
    send(server, {self, message})
    receive do
      {_caller, reply} ->
        IO.puts "#{reply}"
        # Only continue if process is not dead.
        # Comparing against strings is usually not idiomatic, you may want to
        # change that.
        if reply != "Process Dead" do
          loop(server)
        end
    end
  end
end

defmodule PracticeServer do
  def start do
    spawn(&loop/0)
  end

  def loop do
    receive do
      {caller, "kill"} ->
        send(caller, {self, "Process Dead"})
      {caller, _} ->
        send(caller, {self, "Thank you for your message!"})      
        loop    
    end
  end
end

PracticeCaller.start
:timer.sleep(:infinity)

请注意,即使在发送“kill”之后,这也不会停止VM。如果这只是一个脚本,您可以在消息为“进程停止”时将
:erlang.halt
添加到
PracticeCaller.loop/1
,以立即停止VM。

服务器停止后,您希望客户端做什么?我希望客户端也被停止,但是我不知道该怎么做。你希望客户端在服务器死后做什么?我希望客户端也被杀死,但我不知道该怎么做。