从Elixir Process打印到控制台

时间:2016-09-01 15:41:50

标签: erlang elixir

所以,我开始玩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响应。

有关解决这些问题的任何帮助吗?

1 个答案:

答案 0 :(得分:3)

第一个问题是:

public class tblStudiosDTO 
{
    public string Standort { get; set; }
    public string Name { get; set; }
    public string Id { get; set; }
}

以及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!

这是因为Enter a message:kill Thank you for your message! 包含尾随换行符,这意味着IO.gets/1中的{caller, "kill"}模式永远不匹配。

这可以通过更改:

来解决
PracticeServer.loop/0

message = IO.gets "Enter a message:"

现在:

message = IO.gets("Enter a message:") |> String.trim_trailing

另一个问题是您目前正在泄漏流程。您不是重复使用衍生服务器,而是为每条消息生成一个新服务器。此外,处理可被“杀死”的递归Enter a message:kill Process Dead Enter a message:kill Process Dead 的惯用方法是在您希望进程死亡时不执行递归调用。这是一些重构的代码:

receive

请注意,即使发送“kill”,也不会暂停VM。如果这只是一个脚本,当消息为“Process Dead”时,您可以将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) 添加到:erlang.halt以立即停止VM。